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
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.
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.
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.
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.
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.
In this way a class that has many methods can be tested whilst keeping the test code DRY and easy to maintain.
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.