Spec Flow and Friends 4

Machine Specifications has a structure that follows the Arrange Act Assert work flow using ‘establish’, ‘because’ and one or more ‘it’ methods.  That’s great if what you are trying to specify falls neatly into the AAA pattern but what happens when you want to test a method, but give it lots of different parameters values like in the Calculator kata?

You have a few options, you could stick to the pattern, and create a new class for each new set of parameter values

  1. [Subject("Calculator Add")]
  2. public class Calling_add_with_an_empty_string
  3. {
  4.     Establish context =
  5.         () =>
  6.             {
  7.                 _calculator = new Calculator();
  8.             };
  9.  
  10.     Because of =
  11.         () =>
  12.             {
  13.                 _results = _calculator.Add("");
  14.             };
  15.  
  16.     It returns_zero =
  17.         () => _results.ShouldEqual(0);
  18.  
  19.     static int _results;
  20.     static Calculator _calculator;
  21. }
  22.  
  23. [Subject("Calculator Add")]
  24. public class Calling_add_with_one
  25. {
  26.     Establish context =
  27.         () =>
  28.             {
  29.                 _calculator = new Calculator();
  30.             };
  31.  
  32.     Because of =
  33.         () =>
  34.             {
  35.                 _results = _calculator.Add("1");
  36.             };
  37.  
  38.     It returns_one =
  39.         () => _results.ShouldEqual(1);
  40.  
  41.     static int _results;
  42.     static Calculator _calculator;
  43. }

 

This is very long, doesn’t for me read very well and the tests are almost the same, so I end up with a lot of duplicated code. 

The way I like to approach problems like this is to attempt to keep the sprit of the Arrange Act Assert format ensuring I keep the assert methods to a single line, but also allow the Assert to behave like the act via a well named method that encompasses the behaviour that would normally be in the act.

  1. [Subject("Calculator Add")]
  2. public class Calling_add_with
  3. {
  4.     Establish context =
  5.         () => { _calculator = new Calculator(); };
  6.  
  7.     It an_empty_string_returns_0 =
  8.         () => Add("").ShouldEqual(0);
  9.  
  10.     It a_string_containing_one_returns_1 =
  11.         () => Add("1").ShouldEqual(1);
  12.  
  13.     static int Add(string inputString)
  14.     {
  15.         return _calculator.Add(inputString);
  16.     }
  17.  
  18.     static Calculator _calculator;
  19. }

Now the tests are short, very important for maintaining understanding, and contain very little duplicated code, I use this pattern whenever I start to get tests that are very similar but span many specification classes.

With the increasing use of  ORM (Object Relational Mapping) frameworks, Linq to Sql, and the the wish to flatten architectures so that controllers may now get data directly from the database, something I am still not entirely sure about, testing code that reads or writes to a data store has become more difficult.  trying to stub out connections or commands of a data store can take longer and be more complex than the rest of the production code combined!

In these cases it can be better to just let the code access the database (a test version please) and simply tidy up after the test has completed.  But in the format of Arrange, Act, Assert, there is no cleanup phrase.  Machine specifications does have an extra tag that can be used, ‘Cleanup’ is called after all the asserts within the class have been executed.

  1. [Subject("Database Access")]
  2. public class Add_person_to_database
  3. {
  4.     Establish context =
  5.         () =>
  6.             {
  7.                 _personRepository = new PersonRepository();
  8.                 _person = new Person
  9.                               {
  10.                                   FirstName = "Duncan",
  11.                                   LastName = "Butler"
  12.                               };
  13.             };
  14.  
  15.     Because of =
  16.         () =>
  17.             {
  18.                 _personRepository.Store(_person);
  19.             };
  20.  
  21.     It stored_person_should_have_an_id =
  22.         () => _person.Id.ShouldNotBeNull();
  23.  
  24.     It should_be_able_to_retrieve_person_from_database =
  25.         () => _personRepository.Get(_person.Id).ShouldEqual(_person);
  26.  
  27.     Cleanup after =
  28.         () =>
  29.             {
  30.                 using (var dc = new PersonDataContext(""))
  31.                 {
  32.                     dc.Persons.DeleteOnSubmit(_person);
  33.                     dc.SubmitChanges();
  34.                 }
  35.             };
  36.  
  37.     static PersonRepository _personRepository;
  38.     static Person _person;
  39. }

 

Although I personally would prefer to avoid using the cleanup method, and I don’t like my unit tests actually hitting the database, these days with the advent of Linq it has becoming difficult to justify always having a repository class simply to make testing easier, so being able to establish some data in a database during the setup, and cleaning it up after the specification has run can be very useful.

I don’t always test the happy  path, sometimes I may want to catch an exception and check that it is of the correct type or contains the correct message, most test frameworks have a way of catching any exceptions thrown, and Machine Specifications is no different.

  1. [Subject("Calculator Add")]
  2. public class giving_calculator_add_invlid_input
  3. {
  4.     Establish context =
  5.         () =>
  6.             {
  7.                 _calculator = new Calculator();
  8.             };
  9.  
  10.     It a_string_containing_a_negative_number_throws_argument_exception =
  11.         () => Catch.Exception(() => Add("-1")).ShouldBeOfType<ArgumentException>();
  12.  
  13.     It a_stirng_containing_a_negative_number_throws_exception_with_message_containing_number =
  14.         () => Catch.Exception(() => Add("-1")).Message.ShouldContain("-1");    
  15.  
  16.     static int Add(string inputString)
  17.     {
  18.         return _calculator.Add(inputString);
  19.     }
  20.     
  21.     static Calculator _calculator;
  22. }

 

The syntax is a little bit funky but all Catch.Exception does is simply call the method pointed to by () => and catches any exception, this exception is simply returned, or if no exception is thrown it returns null.

Finally when I am looking at tests, most of the time I don’t actually care about the setup, or the cleanup, I care about what is being called, and the results expected from that call, so most of the time I like to push the setup and cleanup code into its own class that my test class can then inherit, never be tempted to push the act (because) method down into a base class, because when reading the tests it is important to know what was called.

  1. [Subject("Database Access")]
  2. public class Add_person_to_database : PersonRepositoryContext
  3. {
  4.     Because of =
  5.         () =>
  6.             {
  7.                 _personRepository.Store(_person);
  8.             };
  9.  
  10.     It stored_person_should_have_an_id =
  11.         () => _person.Id.ShouldNotBeNull();
  12.  
  13.     It should_be_able_to_retrieve_person_from_database =
  14.         () => _personRepository.Get(_person.Id).ShouldEqual(_person);
  15. }
  16.  
  17. public class PersonRepositoryContext
  18. {
  19.     Establish context =
  20.         () =>
  21.             {
  22.                 _personRepository = new PersonRepository();
  23.                 _person = new Person
  24.                               {
  25.                                   FirstName = "Duncan",
  26.                                   LastName = "Butler"
  27.                               };
  28.             };
  29.  
  30.     Cleanup after =
  31.         () =>
  32.             {
  33.                 using (var dc = new PersonDataContext(""))
  34.                 {
  35.                     dc.Persons.DeleteOnSubmit(_person);
  36.                     dc.SubmitChanges();
  37.                 }
  38.             };
  39.  
  40.     protected static PersonRepository _personRepository;
  41.     protected static Person _person;
  42. }

 

This keeps the test classes clean, the context can be shared across many test classes, it is also possible to stack the establish context methods, the parent is called before the child etc, so we are able to override properties within a specification.

  1. [Subject("Database Access")]
  2. public class Add_person_to_database : PersonRepositoryContext
  3. {
  4.     Establish context =
  5.         () =>
  6.             {
  7.                 _person.FirstName = "John";
  8.                 _person.LastName = "Smith";
  9.             };
  10.  
  11.     Because of =
  12.         () =>
  13.             {
  14.                 _personRepository.Store(_person);
  15.             };
  16.  
  17.     It stored_person_should_have_an_id =
  18.         () => _person.Id.ShouldNotBeNull();
  19.  
  20.     It should_be_able_to_retrieve_person_from_database =
  21.         () => _personRepository.Get(_person.Id).ShouldEqual(_person);
  22. }

 

In this way a class that has many methods can be tested whilst keeping the test code DRY and easy to maintain.

That just about covers the basics of SpecFlow and Machine Specifications and how using BDD I combine them to get the best coverage with the minimum of fragility.

Using the two products together, I am able to define what done looks like  at the start of a project, use these definitions to drive the code, dropping down to specifications where finer detail of a class or individual method is required and at the end of a project I have features written as plain text that describe the system at a high level and specifications that describe the functionality at a low level.

I recommend that people interested in learning this style of software development read the “RSpec Book” although it is written around the Ruby Language, as its forward, written by Robert C. Martin states, its not actually about Ruby, that just happens to be the language used for the examples, in the same way as I tend to use C#, what the book is actually about is writing software using best practices, to achieve reliable, maintainable and cost effective code.

Advertisements

About Duncan Butler

Trying to be a very agile software developer, working in C# with Specflow, Nunit and Machine Specifications, and in the evening having fun with Ruby and Rails
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s