Nancy, OWIN and Razor

Nancy, OWIN and Razor

21 November 2015

Microsoft.OWIN.Testing which allows for the testing of an in-memory web based application. I am hoping this will simplify test automation since the amount of scenarios can be reduced to just testing the user flow between pages?

Starting with the test

With the blueprint below, notice that 'Colin' is specified in the uri at the end which is then incorporated in the response.

# GET /razorWithLayout/Colin

+ Response 200 (text/html)

  + Body

    <!DOCTYPE html>
    <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
    <head>
      <meta charset="utf-8"/>
      <title></title>
    </head>
      <body>
        <h1>Hi Colin</h1>
      </body>
    </html>

The test below expects a response with contentType 'text/html' and an h1 element containing 'Hi Colin'. I am using HtmlAgilityPack to load the Html into an HtmlDocument so that I can query using XPath.

[Fact]
public async void RazorOwinWithLayoutTest()
{
  using (var server = TestServer.Create<NancyStartup>())
  {
    var req = server.CreateRequest("/razorWithLayout/Colin");
    var res = await req.GetAsync();

    res.StatusCode.ShouldBeEquivalentTo(HttpStatusCode.OK, "expecting an ok response");
    res.Content.Headers.ContentType.MediaType.ShouldBeEquivalentTo("text/html", "HTML is expected be returned");

    var html = await res.Content.ReadAsStringAsync();
    var htmlDocument = new HtmlDocument();
    htmlDocument.LoadHtml(html);
    htmlDocument.DocumentNode.SelectSingleNode("//h1").InnerText.ShouldBeEquivalentTo("Hi Colin", "expected the correct heading text");
  }
}

What is unique here is that I can validate Html returned from Nancy which has used the Razor views. I may have tried accomplishing this by using Selenium for example?

This means tests can be created to set-up requests and test that the Html has the expected mark-up for a given state.

The Nancy module

public class SampleModule : NancyModule
{
    public SampleModule()
    {
        Get["/hello"] = o => "Hello";
        Get["/razor"] = o => View["Sample"];
        Get["/razorWithLayout/{name}"] = o => View["SampleWithLayout", new {o.name}];
    }
}

It's a simple NancyModule. It's very different from MVC5 where you use attributes or RouteConfig to map requests to controller actions.

The Razor Views

Layout.cshtml is shown below.

@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<dynamic> 
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8"/>
    <title></title>
</head>
    <body>
        @RenderBody()
    </body>
</html>

SampleWithLayout.cshtml is shown below.

@inherits Nancy.ViewEngines.Razor.NancyRazorViewBase<dynamic> 
@{
    Layout = "Layout.cshtml";
}
<h1>Hi @Model.name</h1>

The code

My code is available at Owin.Research

.NET Frameworks OWIN Testing XUnit