Showing posts with label TDD. Show all posts
Showing posts with label TDD. Show all posts

Monday, November 3, 2014

The 'Unit' in a Unit Test

How much should a unit test cover? What is the 'unit' which it should test? This seems to be a recurring discussion among developers. And rightly so - I am not going to claim to have the ultimate answer to those questions, but I will address one misconception that I hear repeated time and again, namely that the 'unit' of a unit test is a class in the production code. In this post I will show why this leads to bad testing practices and how thinking of the 'unit' as a unit of functionality leads to a better place.

Example

To illustrate my point I'll play around with the following Employee class from an imagined resource allocation system. The system handles work assignments and can only assign them to employees that
  • do not have overlapping assignments
  • have the necessary skills
  • cost less per hour than the assignment pays
Instances of Employee have a number of work assignments each of which start at a certain date and likewise ends at a certain date. Employees also have a skill set and a minimum hourly cost. Employee instances use these properties to implement the business rules around work assignments, like so:


The implementation of Employee shown here is simplistic. Real business rules would no doubt be more involved. Nevertheless this class serves to illustrate the point.
If we follow the notion that the 'unit' of a unit test is a production class it is reasonable to assume that there is a test class corresponding to Employee and that it could look something like this:


Refactoring Production Code

Even though the employee class is simplistic it still has several reasons to change:
  • Changes to the business rules around matching employee skill set and assignment requirements
  • Changes to the business rules for employee availability, for instance introduction of part time assignments
  • Changes to the business rules around employee cost ans assignment rate
In other words the Employee class violates the Single Repsonsibility Principle.
As a first refactoring lets introduce a SkillSet class capable of comparing a set of skills held by an employee and a set skill needed by a task:



which would change the Employe class to this (hint: The changes are in line 12 and 19):



At this point the existing tests need just one follow one change in its constructor:


After that the tests will pass again and - importantly - they will still cover all our code including the SkillSet class.

Refactoring the Test Code?

The Employee_should class now tests not only the Employee class but also the SkillSet class. If we assume that the 'unit' of a unit test is a production class Employee_should is no longer a unit test. Following this line of thought leads towards two changes to the test code:
  • Mock out the SkillSet in the Employee_should. Typically this involves first introducing an interface on top of SkillSet and then using a mocked version of that in the Employee_should
  • Create a new test class for the SkillSet - Skillset_should

I'm not going to write that code, but I'm sure you can imagine it.

Test Code Smell

If we went ahead and did the refactorings to our test code it would be becoming quite smelly:
  • We would have lost all testing of the collaboration between Employee and SkillSet. This is pretty serious since that is in fact where part of the business rules are upheld. These parts of the rules would effectively become untested.
  • The Employee_should test class would become more complicated by the extra setup of the mocked SkillSet - this might not seem too bad at this point, but quickly becomes unwieldy when dealing with more complicated scenarios
  • The Skillset_should test would not add much - it almost just checks that the framework method IsSubsetOf works.

If we, on the other hand, follow the line of thought that the 'unit' of a unit test is a unit of behavior, we would just keep the unit tests as the are after the introduction of the SkillSet class. This is better because the tests are not hampering the freedom to refactor the production code.

Conclusion

I find it much more helpful to think about the 'unit' in unit test as a unit of behavior. Whether that unit of behavior is implemented in one or more production classes is an implementation detail of the production code.

Sunday, September 1, 2013

From Fact to Theory

I often find that the tests I write can be slowly generalized as the feature I happen to be working on is fleshed out. In xUnit.net terms I find that a fair number of the tests tend to move through these four stages:
  1. Start out as a single [Fact], working on hardcoded input data
  2. Pull out the hardcoded data, turning the tests into a [Theory, AutoData]
  3. Add edge cases, evolving the test into [Theory, AutoData, InlineData, InlineData]
  4. Add cases representative of equivalence classes, thus adding more InlineData attributes to the test
Each of the stages generalizes the test a bit more making it more potent in several ways. As the test moves through each stage it gains greater coverage in terms of the possible inputs, making it a better regression guard. But there is more at play. Along with the generalization (and multiplication) of the inputs the test can often be refactored towards being more about the behavior of the SUT and less about its implementation. So alongside the four stages above I find tests tend to move through these stages as well:
  1. While being a [Fact] the test is named something very specific - a specific example of how the SUT should behave
  2. During stage 2 or 3 the test name becomes something that expresses a general trait of the SUT
  3. The assertions in the test becomes less dependent on implemntation details
I am not always able to make my tests follow either of these progressions, but when I am I find it very rewarding.

Thursday, June 27, 2013

My Nancy Talk from NDC

The video of the talk I did on Nancy at NDC is out.

The talk me writing some Nancy code, talking a lot about Nancy and at the end I have a simple todo application.

Enjoy!


Friday, May 3, 2013

PowerShell, Tests and CI/D

Maybe you have an ASP.NET web site, and maybe you have a collection of PowerShell modules used for various automation tasks, like moving files between environments, kicking off batch processes, moving assets to the your CDN or similar things. If so these bits of PowerShell contain important bits of logic; if they don't work your site doesn't work properly.

Naturally you want to apply the same discipline to the PowerShell code as to any other production code, which includes TDD and Continuous Integration/Delivery/Deployment (CI/D). Furthermore I'll assume that you already have tests around your C# code, and that your CI/D setup runs these tests and reports the result.

In this situation you can TDD by writing test functions in the PowerShell modules themselves and call them from the command line. This, of course, becomes tiresome quickly as the number of tests rise, so you'll soon find yourself  writing ad hoc test runners for each PowerShell module. This works. Sort of. But it's still tiresome to run the tests selectively, and just as importantly, this doesn't fit into your CI/D setup which is geared towards your xUnit (or similar) test suites.

One quick and simple way to get around this issue is to write the tests in C# just as any other tests and simply call the PowerShell from there. Like so:



This isn't perfect:

  • It's somewhat slow. 
  • The call out to the PowerShell under test is tugged away inside a string.Format call
  • The tests and the code under test are written in different languages, which doesn't sit well with me. It introduces an odd asymmetry and it creates an artificial barrier between the tests and the code under test.
The big win on the other hand is that it fits right into your existing TDD and CI/D setup.

Monday, July 9, 2012

WPF View Smoke Testing

I enjoy TDD. I enjoy the way it makes me code and I enjoy the rhythm. That is, I really enjoy TDD'ing the logic in my applications: The business logic, the controller logic, the domain logic; wherever there is logic that I can isolate and unit test cleanly TDD is just all fun and productivity. I enjoy TDD'ind integration points a little less: The database access, the web service calls, and so on are slow to test, so the TDD rhythm is broken. I still prefer TDD'ing these parts too though. I do not enjoy TDD'ing UIs: In my experience the tests are slow, either the rate of false negatives is high or the rate of false positives is high, and UI test are a pain to write (don't even get me started on the horrors of recording UI tests). Therefore I usually settle for subcut tests and manual UI testing when it comes to views. That is: I want to TDD my presentation logic, but am usually ok with checking that the pixels are in the right spot manually.
Working with WPF this is - at first sight - supported by MVVM: The view models sit right under the views, and are able to cut the .xaml.cs code behinds down to (almost) nothing, so testing the view models is subcut testing right? Right?? Not quite: There is a little bit of stuff going on in the bindings. I want to test that stuff.

WPF has been around for a while so I expected this to be a solved problem. Maybe it is, but my googling didn't yield an answer. It did however yield a number of candidated solutions. Below is a quick summary of my evaluation I of these candidates. (TLDR: None of the libraries worked, but Window.Show and FrameworkElement.FindName turned out to be my friend, and maybe, just maybe. Approval Tests could finally win me over to UI testing).

Notes From My Evaluation

Below there is a section for each of the candidates I quickly evaluated with some rough notes on how it went. The evaluations are not terrible thorough nor objective, so YMMV 

IcuTest

IcuTest is a library that works by asking you the first time a test is run to accept or reject the result: It shows you a snapshot of the window to assert on, and you accept or reject. If you accept the image is saved and used as the acceptance criteria in subsequent runs.
I have a few issues with this: The asserts come down to bitmap comparisons, which means (1) that they are imprecise - they assert on the whole window/control instead of just the one thing the current test is about and (2) they depend on the machine the test is running on. These are execatly the issues with UI testing that have bitten me in the past. So IcuTest is not what I'm after.

White

White seems to be the most grown up UI testing framework for Windows applications around. Promising. But: I installed the NuGet in my projects and was immediately sent into the Log4Net strong naming cirkus. Annoying but not Whites fault.I went on to clone the source off Github. It compiled out of the box, but most of the tests failed. After fiddling around for a few hours I got like 60% of the tests running. Not a good sign to be honest. The fiddling included changing things like which properties were used to input text into a textbox in ways that were pure guessing on my part. All in all this seemed like a route that would lead to unstable tests. So White is not what I'm after.

AvalonTestRunner

The AvalonTestRunner is an old thing from back when WPF was still Avalon. It doesn't claim to do a lot either. But none of these are bad things in themselves. If it works it works. One of the things AvalonTestRunner claims to do is sanity check all the bindings in a view: I.e. throw an exception if there is a binding path that is not found in the data context. That is part of what I'm after and actually a quite nice first line of defense to have. Only problem: I couldn't get it to work, not out of the box and not after debugging through the source for a while. Maybe it's just me, but again I concluded: AvalonTestRunner is not what I'm after.

Guia

Guia seems to try to solve the same thing as white but only for WPF. It also seems defunct: The current version is 0.1.1 and is 2 years ole (at the time of writing) . But again: If it works it works. Sadly it didn't work out of the box, and because of the lack of activity I didn't investigate further. Guia is not what I'm after.

Hand Coding

With all the libraries I tried out not really working I'm left with hand coding the tests myself. As it turns out this is in fact not nearly as bad as it sounds  - not for the subcut type of tests I'm after anyway.

MS UI Automation lib

MS UI Automation is a library intended to support building screen readers, remote controls and other types of applications that need to automate the UI of some other - known or unknown - application. It seems to provide everything you'd need to write UI test for WPF. I haven't tried it out though because it seems like overkill for what I'm looking for.

.FindName

As it turns out I probably shouldn't have spent so much time wading through testing libraries because the simple little kinds of tests I set out to write: Tests that drive and check the bindings in my XAML are actually (for the most part at least) easily written by just opening the window under test directly, finding the controls of interest by calling .FindName on the window under test and then manipulating or asserting against properties on those controls. Like this:

This is so darn easy, that once I realized, that this is actually what I am after I stopped looking at libraries although there are still a couple on my list. So there you have it: It's just not complicated enough to need a library.

Promising ones I haven't gotten around to evaluating

In spite of the conclusion above the following may be worth checking out. I'm pretty sure at least ApprovalTests work although I haven't tried it. WhiPFlash seems active, but beyond that I know nothing.

ApprovalTests

WhiPFlash

Monday, December 5, 2011

Announcing: XmlUnit.Xunit


I wanted to announce a small library I have on my GitHub: XmlUnit.Xunit, which a library for testing against XML. It's a port of XmlUnit over to use Xunit.NET assertions instead of NUnit assertions, plus an addition of a fluent assertion style. The following is the projects README, and gives you a feel for the purpose of the project. Enjoy.

Intro

XmlUnit.Xunit provides Xunit.NET based assertions tailored to testing XML. The project contains assertions for comparing XML, applying XPath and XSLT expression to XML under test. All assertions come in two flavors: A traditional set of static assertion methods, and a fluent "should" style assertions.


Usage
You grab the source from here, download a build from here or install the NuGet package.

Beware that both the binary in the download tab and the NuGet package may give you assembly conflicts on Xunit.NET. To get around that you need an assmebly rebind of Xunit.NET.

Traditional Assertions
The traditional assertions in XmlUnit.Xunit er all static methods on the class XmlAssertion, and are used like this:

  404 [Fact]
  405 public void AssertStringEqualAndIdenticalToSelf()
  406 {
  407     string control = "<assert>true</assert>";
  408     string test = "<assert>true</assert>";
  409     XmlAssertion.AssertXmlIdentical(control, test);
  410     XmlAssertion.AssertXmlEquals(control, test);
  411 }
  412 
  413 private static readonly string MY_SOLAR_SYSTEM =
  414     "<solar-system><planet name='Earth' position='3' supportsLife='yes'/><planet name='Venus' position='4'/></solar-system>";
  415 
  416 [Fact]
  417 public void AssertXPathExistsWorksForExistentXPath()
  418 {
  419     XmlAssertion.AssertXPathExists("//planet[@name='Earth']",
  420                                    MY_SOLAR_SYSTEM);
  421 }
  422 
  423 [Fact]
  424 public void AssertXPathEvaluatesToWorksForMatchingExpression()
  425 {
  426     XmlAssertion.AssertXPathEvaluatesTo("//planet[@position='3']/@supportsLife",
  427                                         MY_SOLAR_SYSTEM,
  428                                         "yes");
  429 }
  430 
  431 [Fact]
  432 public void AssertXslTransformResultsWorksWithStrings()
  433 {
  434     string xslt = XsltTests.IDENTITY_TRANSFORM;
  435     string someXml = "<a><b>c</b><b/></a>";
  436     XmlAssertion.AssertXslTransformResults(xslt, someXml, someXml);
  437 }
  438 


Fluent Assertions
The fluent assertions are all extension methods with names starting with Should, and are used like this:

  404 [Fact]
  405 public void AssertStringEqualAndIdenticalToSelf()
  406 {
  407     string control = "<assert>true</assert>";
  408     string test = "<assert>true</assert>";
  409     test.ShouldBeXmlIdenticalTo(control);
  410     test.ShouldBeXmlEqualTo(control);
  411 }
  412 
  413 private static readonly string MY_SOLAR_SYSTEM =
  414     "<solar-system><planet name='Earth' position='3' supportsLife='yes'/><planet name='Venus' position='4'/></solar-system>";
  415 
  416 [Fact]
  417 public void AssertXPathExestsWorksForXmlInput()
  418 {
  419     new XmlInput(MY_SOLAR_SYSTEM)
  420         .XPath("//planet[@name='Earth']")
  421         .ShouldExist();
  422 }
  423 
  424 [Fact]
  425 public void AssertXPathEvaluatesToWorksForMatchingExpression()
  426 {
  427     MY_SOLAR_SYSTEM
  428         .XPath("//planet[@position='3']/@supportsLife")
  429         .ShouldEvaluateTo("yes");
  430 }
  431 
  432 [Fact]
  433 public void AssertXPathExistsWorksWithXpathFirstWithXmlInput()
  434 {
  435     var sut = new XmlInput(MY_SOLAR_SYSTEM);
  436 
  437     "//planet[@name='Earth']".AppliedTo(sut).ShouldExist();
  438 }
  439 
  440 [Fact]
  441 public void AssertXPathEvaluatesToWorksWithXPathFirst()
  442 {
  443     "//planet[@position='3']/@supportsLife"
  444         .AppliedTo(MY_SOLAR_SYSTEM)
  445         .ShouldEvaluateTo("yes");
  446 }
  447 
  448 [Fact]
  449 public void AssertXslTransformResultsWorksWithStrings()
  450 {
  451     string xslt = XsltTests.IDENTITY_TRANSFORM;
  452     string someXml = "<a><b>c</b><b/></a>";
  453 
  454     someXml.XsltTransformation(xslt).ShouldResultIn(someXml);
  455 }

Further Information
Is probably best gleened off the tests in this project, especially the tests for XmlAssertions and the tests for Should assertions.

Contribute
Please do! Fork, code, send pull request. :-)

Monday, October 24, 2011

Frictionless .NET Web App Development with Nancy Part III - Introducing MongoDB

Continuing the URL shortener sample from thesse post: part I and part II, I'll go from (stupidly) storing the shortened URLs in a static variable, as was the case in the code in part I, to storing the shortened URLs in MongoDB. The reasons for choosing MongoDB for persistence in this sample (compared to the "traditional" NHibernate + SQL Server approach) are:
  • We will only store and retrieve one document at a time. Those are atomic operations in Mongo, so as far as this sample goes Mongo is fully consistent.
  • Mongo is simple to setup, and very simple to code against. For instance there is no O/R mapping layer at all.

In summary, Mongo is a nice frictionless option for this sample.

Enough talk, show me the code!

Decoupling interface from persistence
The first thing to do is to pull the persistence related code out of the Nancy module. We use the following couple of tests to drive that. They use a Moq mock to specify the interface to the persistence code; that is the UrlStore interface:

    1 namespace ShortUrlTest
    2 {
    3   using Xunit;
    4   using Nancy.Testing;
    5   using Moq;
    6   using ShortUrl;
    7 
    8   public class UrlStorageTest
    9   {
   10     private Browser app;
   11     private Mock<UrlStore> fakeStorage;
   12 
   13     public UrlStorageTest()
   14     {
   15       ShortUrlModule artificiaReference;
   16 
   17       //Given
   18       fakeStorage = new Mock<UrlStore>();
   19       app = new Browser(
   20               new ConfigurableBootstrapper(
   21                 with => with.Dependency(fakeStorage.Object)));
   22 
   23     }
   24 
   25     [Fact]
   26     public void app_should_store_url_when_one_is_posted()
   27     {
   28       //When
   29       app.Post("/",
   30         with =>
   31         {
   32           with.FormValue("url", "http://www.longurlplease.com/");
   33           with.HttpRequest();
   34         });
   35 
   36       //Then
   37       fakeStorage
   38         .Verify(store =>
   39                 store.SaveUrl("http://www.longurlplease.com/", 
   40                               It.IsAny<string>()));
   41     }
   42 
   43     [Fact]
   44     public void app_should_try_to_retrieve_url_when_getting_a_short_url()
   45     {
   46       //When
   47       app.Get("/shorturl",
   48         with => with.HttpRequest());
   49 
   50       //Then
   51       fakeStorage
   52         .Verify(store => 
   53                 store.GetUrlFor("shorturl"));
   54     }
   55   }
   56 }
   57 

A few interesting things go on in these tests.

Firstly, as stated above they specifify the interface UrlStore. They do so via the mock fakeStorage, and the calls to fakeStorage.Verify(...) which tells us that UrlStore should have two methods, SaveUrl and GetUrlFor.


Secondly we again use the Nancy.Testing.Browser type to call into the ShortUrl Nancy module. Remember that this goes though the whole Nancy pipeline, just like a real request from a browser. So we're genuinely testing the module from the outside. In the first test we do a HTTP POST, and in the second one we do a HTTP GET.


Thirdly in the constructor we're using another feature of Nancy.Testing; the ConfigurableBootstrapper. To understand this bit, a little detour is required. Nancy is very modular, everything in Nancy can be swapped for an alternative implementation via configuration. Furthermore Nancy apps uses IoC/DI from the get go. Out of the box Nancy uses TinyIOC, but that can (of course) be swapped with any other container - and NuGets exists for most (if not all) popular containers. The swapping out of things in Nancy apps is done through code, in a bootstrapper, which is a class in the app that implements INancyBootstrapper, and sets up the whole of Nancy and the app. To make this easy Nancy provides the DefaultNancyBootstrapper which can be used as the base class for app specific bootstrappers. Back to tests above. The ConfigurableBootstrapper, provides a simple way for tests to create specialized configurations through a fluent interface. The contructor in the code above registers the mock UrlStore as a dependincy, which means registering it in the TinyIOC container. In other words the parts of a the app that receives a UrlStore from the container will get the mock one when in the context of these tests.

But the UrlStore interface doesn't exists, so lets write it to make the tests compile:

    1 namespace ShortUrl
    2 {
    3   public interface UrlStore
    4   {
    5     void SaveUrl(string url, string shortenedUrl);
    6     string GetUrlFor(string shortenedUrl);
    7   }
    8 }

The tests don't run yet though, since our app does not use UrlStore at all. To make it do so, we change the application code to take a UrlStore in the module contructor, and use it for storage (particularly lines 7, 14 and 22):

    1 namespace ShortUrl
    2 {
    3   using Nancy;
    4 
    5   public class ShortUrlModule : NancyModule
    6   {
    7     public ShortUrlModule(UrlStore urlStore)
    8     {
    9       Get["/"] = _ => View["index.html"];
   10       Post["/"] = _ => ShortenUrl(urlStore);
   11       Get["/{shorturl}"] = param =>
   12       {
   13         string shortUrl = param.shorturl;
   14         return Response.AsRedirect(urlStore.GetUrlFor(shortUrl.ToString()));
   15       };
   16     }
   17 
   18     private Response ShortenUrl(UrlStore urlStore)
   19     {
   20       string longUrl = Request.Form.url;
   21       var shortUrl = ShortenUrl(longUrl);
   22       urlStore.SaveUrl(longUrl, shortUrl);
   23 
   24       return View["shortened_url", new { Request.Headers.Host, ShortUrl = shortUrl }];
   25     }
   26 
   27     private string ShortenUrl(string longUrl)
   28     {
   29       return "a" + longUrl.GetHashCode();
   30     }
   31   }
   32 }
   33 

And that makes the above tests run. But the end-to-end tests shown in part I don't run. The reason is they don't register a UrlStore with the container. They use the DefaultNancyBootstrapper, where no UrlStore is setup. To get past this we need to do a few things: Change the end-to-end tests to use an app specific bootstrapper, create an implementation of UrlStore that uses Mongo, and create an app specific bootstrapper. We'll start by driving out the Mongo implementation of UrlStore.

Shifting gears
To implement UrlStore against Mongo we need to shift TDD gears to using integration tests. The following tests, that drive the implementation of MongoUrlStore assume a Mongo server is running on localhost at port 27010:

    1 namespace ShortUrlTest
    2 {
    3   using System.Linq;
    4   using MongoDB.Bson;
    5   using MongoDB.Driver;
    6   using MongoDB.Driver.Builders;
    7   using ShortUrl.DataAccess;
    8   using Xunit;
    9 
   10   public class MongoUrlStoreTest
   11   {
   12     private string connectionString = "mongodb://localhost:27010/short_url_test";
   13     private MongoDatabase database;
   14     private MongoCollection<BsonDocument> urlCollection;
   15 
   16     public MongoUrlStoreTest()
   17     {
   18       //given
   19       database = MongoDatabase.Create(connectionString);
   20       urlCollection = database.GetCollection("urls");
   21         urlCollection.RemoveAll();
   22     }
   23 
   24     [Fact]
   25     public void should_store_urls_in_mongo()
   26     {
   27       //when
   28       var store = new MongoUrlStore(connectionString);
   29       store.SaveUrl("http://somelongurl.com/", "http://shorturl/abc");
   30 
   31       //then
   32       var urlFromDB = urlCollection
   33         .Find(Query.EQ("url", "http://somelongurl.com/"))
   34         .FirstOrDefault();
   35 
   36       Assert.NotNull(urlFromDB);
   37       Assert.Equal(urlFromDB["shortenedUrl"], "http://shorturl/abc");
   38     }
   39 
   40     [Fact]
   41     public void should_be_able_to_find_shortened_urls()
   42     {
   43       //given
   44       var store = new MongoUrlStore(connectionString);
   45       store.SaveUrl("http://somelongurl.com/", "http://shorturl/abc");
   46 
   47       //when
   48       var longUrl = store.GetUrlFor("http://shorturl/abc");
   49 
   50       //then
   51       Assert.Equal("http://somelongurl.com/", longUrl);
   52     }
   53   }
   54 }
   55 

These two test cases simply use the UrlStore interface, but also go directly to the Mongo instance to check that things are stored there. This is all quite straight forward, the one thing to notice though is that these test only assume that there is a Mongo server running, not that there is any particular database or collection present from the start. This is one of the ways Mongo is easy to work with, the databases and collections used in the code are just created for us behind the scenes. No friction.
To satisfy these tests we simply implement the UrlStore interface as follows:

    1 namespace ShortUrl.DataAccess
    2 {
    3   using System.Linq;
    4   using MongoDB.Bson;
    5   using MongoDB.Driver;
    6   using MongoDB.Driver.Builders;
    7 
    8   public class MongoUrlStore : UrlStore
    9   {
   10     private MongoDatabase database;
   11     private MongoCollection<BsonDocument> urls;
   12 
   13     public MongoUrlStore(string connectionString)
   14     {
   15       database = MongoDatabase.Create(connectionString);
   16       urls = database.GetCollection("urls");
   17     }
   18 
   19     public void SaveUrl(string url, string shortenedUrl)
   20     {
   21       urls.Insert(new {url, shortenedUrl});
   22     }
   23 
   24     public string GetUrlFor(string shortenedUrl)
   25     {
   26       var urlDocument =  
   27         urls
   28           .Find(Query.EQ("shortenedUrl", shortenedUrl))
   29           .FirstOrDefault();
   30 
   31       return 
   32         urlDocument == null ? 
   33         null : urlDocument["url"].AsString;
   34     }
   35   }
   36 }

The thing I really want to point out here is line 21. We just tell Mongo to store an anonymous object and the driver does the rest for us (i.e. serializes it to json). No O/R mapping code!
Now we have an interface for persisting things, our module uses that interface, and we have an implemtation of it against Mongo. The only thing remaining is wiring things up.

Shifting gears back the end-to-end tests
As mentioned earlier the end-to-end tests from part I don't run right now, to make them run we first change their setup to use an app specific bootstrapper:

   14    public BaseUrlSpec()
   15    {
   16      ShortUrlModule artificiaReference;
   17      app = new Browser(new Bootstrapper());
   18    }

We've changed line 17 to use Bootstrapper instead of DefaultNancyBootstrapper. The type Bootstrapper does not exists yet, so lets create it, and have it register MongoUrlStore with the container:

    1 namespace ShortUrl
    2 {
    3   using Nancy;
    4   using DataAccess;
    5 
    6   public class Bootstrapper : DefaultNancyBootstrapper
    7   {
    8     protected override void ConfigureApplicationContainer(TinyIoC.TinyIoCContainer container)
    9     {
   10       base.ConfigureApplicationContainer(container);
   11 
   12       var mongoUrlStore = new MongoUrlStore("mongodb://localhost:27010/short_url");
   13       container.Register<UrlStore>(mongoUrlStore);
   14     }
   15   }
   16 }

We use the DefaultNancyBootstrapper as a starting point, and just use one its hooks to do a little bit of app specific setup, namely registering MongoUrlStore. Using other overrides we could configure anything in Nancy. I really like that a lot.

Well that's it. All tests run again.

Updated code is a available on GitHub.

Monday, October 10, 2011

Frictionless .NET Web App Development with Nancy


This post is about a low ceremony approach to web apps in .NET. It's about just writting the app, without the framework getting in the way. It's about the same sort of feeling that Mogens Heller Grabe talks about with his notion of frictionless persistence with MongoDB. Only here it's about the web part.

I'll take you through a short and simple URL shortener sample app done with the Nancy web framework. A couple of more posts will probably follow on the subjects of view engines, persistence and hosting for this app. Also with an eye on low ceromony and frictionsless development.

What is Nancy? 
Nancy is a lightweight open source web framework in .NET. It has a declared goal of being the developers super-duper-happy-path. Nancy is lightweight in the sense that the number of concepts and the amount syntax you have to grok is minimal. That's why I like it, and that's why it provides the frictionless experience I'm after here.

First things first: The first red-green cycle
One of the first very nice things to notice about Nancy is that it supports TDD really well (much more so than ASP.NET MVC), so lets start looking at the sample by looking at the first test:

    9 public class BaseUrlSpec
   10 {
   11   [Fact]
   12   public void should_respond_ok()
   13   {
   14     var app = new Browser(new DefaultNancyBootstrapper());
   15     var response  = app.Get("/", with => with.HttpRequest());
   16     var statusCode = response.StatusCode;
   17     Assert.Equal(HttpStatusCode.OK, statusCode);
   18   }
   19 }

This is just an ice breaker test to get us going: It just tests that our app responds with an http 200 OK status code. There are nevertheless a couple of things to notice:
  1. Nancy.Testing provides us with the Browser class, which gives our tests an easy way to interact with the app as if they were a browser: The browser object allows for doing GET, PUT, POST and DELETE, PATCH and OPTIONS against the app, including setting up the body, the headers and the protocol. In the case of the above we're doing a GET over http to the relative URL "/", no body, no special headers.
  2. Nancy.Testing also provides a BrowserResponse type that allows for testing all sorts of things on the response from the app. The variable 'response' in the above has this type. Here we just check the status code, but in later examples we'll do a lot more.
There, that's the red part.

To make this run we only have to write this little snippet of Nancy based code:

    4   using Nancy;
    5 
    6   public class ShortUrlModule : NancyModule
    7   {
    8     public ShortUrlModule()
    9     {
   10       Get["/"] =_ => HttpStatusCode.OK;
   11     }
   12   }

Firstly this little piece of code shows the central concept of Nancy: It provides a DSL for responding to http requests. It does so by letting you specify what code should run on GET, PUT, POST, DELETE, PATCH and OPTIONS requests for different URIs. In the above we only specify one such action for one URI: GET for '/'. Secondly it shows another defining trait of Nancy: The framework really tries to make things easy for you, in this case illustrated by the fact we just return a 200 OK status code, but Nancy accepts that and turns it into a full response for us.

GETting the form
So returning a 200 OK does not make for much of an app. What we want here is a very simple URL shortener, so lets turn the front page of the app into a form with a field for the URL the user wants shortened and a submit button. Again we start with a test:

   28     [Fact]
   29     public void should_contain_a_form_with_an_input_field_for_a_url_and_a_button()
   30     {
   31       //when
   32       var baseUrlGetResponse = app.Get("/", with => with.HttpRequest());
   33 
   34       //then
   35       baseUrlGetResponse.Body["form"]
   36         .ShouldExist();
   37 
   38       baseUrlGetResponse.Body["input#url"]
   39         .ShouldExistOnce();
   40 
   41       baseUrlGetResponse.Body["label"]
   42         .ShouldExistOnce().And
   43         .ShouldContain("Url: ");
   44 
   45       baseUrlGetResponse.Body["input#submit"]
   46         .ShouldExistOnce();
   47     }

Here we see some more of Nancys test emphasis: The BrowseResponse type mentioned above provides a Body property that lets our tests search through the body of the response using CSS selectors and make assertions on the results using a set of fluent 'Should' style extensions. For instance the above asserts that there is exactly one input tag with the id 'url' and that there is one label tag which furthermore contains the text 'Url: '. This, I must sat, is just awesome, and is a very good level to test at: Just below the pixels of the UI, and just above the real http stack of the real web server.

To make this run we need only do slightly more than in the previous cycle: We alter the application code to this:

 4   using Nancy;
 5 
 6   public class ShortUrlModule : NancyModule
 7   {
 8         public ShortUrlModule()
 9         {
10           Get["/"] = _ => View["index.html"];
11         }
12   }

and add the following index.html file to a Views folder:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
   <html>
     <body>
       <form method="post">
       <label>Url: </label>
      <input type="text" name="url" id="url"/>
      <input type="submit" value="shorten" id="submit"/>
    </form>
  </body>
</html>

Now we see Nancy trying to make things easy again: Just indicate in the application code that you want to return a view by saying View["index.html"], and Nancy looks in your views folders, finds the view and off we go.

POSTing the form
Next step is reacting to a POST of the form we just made, by shortening the URL. Let's set up a test for that:

 49     [Fact]
 50     public void should_return_shortened_url_when_posting_url()
 51     {
 52       //when
 53       var baseUrlPostResponse = app.Post("/",
 54         with =>
 55         {
 56           with.FormValue("url", "http://http://www.longurlplease.com/");
 57           with.HttpRequest();
 58         });
 59 
 60       baseUrlPostResponse.Body["a#shorturl"]
 61         .ShouldExist().And
 62         .ShouldContain("http://");
 63     }

Here we see how the app object is used for sending a POST to the app, and along with it the appropriate form values; in this case just the url. This starts to show the flexibility and ease of use of the Browser type.

Considering how we've handled the GET request until now, handling the POST is as straightforward:

 3   using System.Collections.Generic;
 4   using Nancy;
 5 
 6   public class ShortUrlModule : NancyModule
 7   {
 8         private static readonly Dictionary<string, string> urlMap = new Dictionary<string, string>();
 9 
10         public ShortUrlModule()
11         {
12             Get["/"] = _ => View["index.html"];
13             Post["/"] = _ => ShortenUrl();
14         }
15 
16         private string ShortenUrl()
17         {
18             string longUrl = Request.Form.url;
19             var shortUrl = ShortenUrl(longUrl);
20             urlMap[shortUrl] = longUrl;
21 
22             return ShortenedUrlView(shortUrl);
23         }
24 
25         private string ShortenUrl(string longUrl)
26         {
27             return "a" + longUrl.GetHashCode();
28         }
29 
30         private string ShortenedUrlView(string shortUrl)
31         {
32             return string.Format("<a id=\"shorturl\" href=\"http://{0}/{1}\">http://{0}/{1}</a>", Request.Headers.Host, shortUrl);
33         }
34     }

This is all pretty straight forward. The Nancy parts of this are:
  1. The use of POST...which does just what you expect.
  2. The return of a string in the last method. That bubles all the way up, and becomes the repsonse back to Nancy. Again Nancy is nice to us, sets the content type to text/html and the status code to 200 OK. This is not the nicest code on my part, so I might just return to refactor it in a future post.
The above of course is not very clever about the shortening, and does not exactly persist the short URLs in a good permanent place. I'll return to the persistence in a furture post.

Redirect
Only one part is missing for a simplistic but functioning URL shortener: The app must redirect the shortened URLs to the original longer one.
Again lets start with the test:

 65     [Fact]
 66     public void should_redirect_to_original_url_when_getting_short_url()
 67     {
 68       //when
 69       var baseUrlPostResponse = app.Post("/",
 70         with =>
 71         {
 72           with.FormValue("url", "http://www.longurlplease.com/");
 73           with.HttpRequest();
 74         }).GetBodyAsXml();
 75 
 76       var shortUrl = baseUrlPostResponse
 77         .Element("a")
 78         .Attribute("href").Value
 79         .Split('/')
 80         .Last();
 81 
 82       //then
 83       app.Get("/" + shortUrl, with => with.HttpRequest())
 84         .ShouldHaveRedirectedTo("http://www.longurlplease.com/");
 85     }

We do the POST again, find the short URL with a bit of LINQ-to-xml and then do a GET to that. And then just assert that the redirect happened. Pretty straight forward except maybe for the Linq-to-xml part.

To make the last test run we add this to our application code:

 14  Get["/{shorturl}"] = param =>
 15  {
 16     string shortUrl = param.shorturl;
 17     return Response.AsRedirect(urlMap[shortUrl.ToString()]);
 18  };


which is an action for a whole set of URIs, namely the URIs matching the URI template "/{shorturl}". In the action we access the 'shorturl' part of the URI through the param.shorturl; all parts of the templatized URI will be availbe like that through the dynamic param. Nice.

That's it. We have a simplistic URL shortener. No friction.

The source is availble on github, and more Nancy information is avaible on the Nancy web site.