xUnit.GWT – Given When Then (GWT) extension for xUnit.net

One of the most important considerations when writing automated tests, especially customer acceptance tests is readability. I have been looking at how you could potentially create more readable tests targeted against C# applications. While I have spoke before about IronRuby and RSpecCucumber as customer acceptance tests for C# applications, this combination still has some performance issues together with an initial ‘fear factor’ for some users.

One of the reasons why I created this framework was based on previous experiences of introducing new concepts. Attempting to introduce too many new concepts to a team unfamiliar with the idea can be a huge challenge. Team members focus too much on the amount of information they have to learn instead of focusing on the concept and how it can be applied.

In an attempt to combat this, I have created a prototype which approaches the topic of creating customer acceptance tests in a similar fashion to cucumber, however in the familiarity of C#. While you could successfully write your tests like this, my aim is to use this as a gateway to move people onto other frameworks such as Cucumber via IronRuby.

The code for this can be found on my GitHub repository. For those of you following me on twitter, you will be aware that this code has been available for a while – I’ve only just managed to find time the time to write a post about the framework. If you want to stay up to date, I recommend to stay up to date is follow me on twitter, GitHub and of course my blog.

Back on to the prototype. It is called xUnit.GWT and builds on top of the amazing extensibility model xUnit has in place.

Example

[Feature("As a user... I want to... So that I...")]
public class This_is_my_story : This_is_my_story_Base
{
        [Scenario]
        public void when_transferring_between_two_accounts()
        {
            Given("both accounts have positive balances");           
            When("transfer money from a to b");
            Then("a should have the total balance of b", () => a.Balance.ShouldBe(3));
            Then("balance of b should be 0", () => b.Balance.ShouldBe(0));
        }
}

The above code is an example of how a test would look with this prototype. This can be executed using TestDriven.NET, ReSharper and the xUnit.Console itself.

First, lets focus on the class. The class has an attribute called Feature. This should define the feature which the various different scenarios relate to. The scenarios are methods within the class.  These methods has been flagged with the attribute Scenario so xUnit can detect and execute them.

Each scenario is then broken down into three different stages. Each of the Given, When, Then statements are in fact method calls with two overloads. One just accepts a string, while the other accepts a string and a delegate.

The reason we can simply pass in a string, is because the associated delegate has already been set within a base class.  An example base class is shown here.

public class This_is_my_story_Base : Story
{
    protected Account a;
    protected Account b;

    public This_is_my_story_Base()
    {
        SetGiven("both accounts have positive balances", () =>
                                                             {
                                                                 a = new Account();
                                                                 a.Balance = 1;
                                                                 b = new Account();
                                                                 b.Balance = 2;
                                                             });

        SetWhen("transfer money from a to b", () =>
                                                  {
                                                      a.Balance += b.Balance;
                                                      b.Balance = 0;
                                                  });
    }
}

The use of SetGiven or SetWhen allows us to store re-usable blocks of code. Using the string as a key, in our subclass we can use the same key to indicate which block of code should be executed. The aim is that these blocks of code should be reusable enough to allow different scenarios to make use of them and as such improve the readability of our tests.

While playing around, I found this sometimes caused too much overhead which is why you can simply pass in the delegate to execute within the method call. Using the explicit approach when defining your Then’Assertions can actually improve the readability.

With this structure in place, we can now start becoming more flexible. One thing I found when working on test harnesses at Red Gate is that you want to write the boiler plate test while it is fresh in your head, even if the actual implementation is not in place. Having these in place can also provide a good indication of the state of the project. If the test is still pending – it isn’t done.

To cope, you can pass in a delegate called Pending. When you execute the scenario the test will be skipped and not executed.

[Scenario]
public void test_marked_as_pending()
{
    Given("one pending block", Pending);
    Then("it should be marked as pending in the report");
}

The same applies in case you haven’t provided an implementation for anyone of the blocks you are attempting for use.

[Scenario]
public void pending_block()
{
    Given(“a block which has been defined”);
    When(“no action assigned”);
    Then(“it should be marked as pending”);
}

Yet, this is not the whole story. Another problem I commonly experienced was with the NUnit report embedded into CCNet. Even if you have take the effort to make your namespaces, classes and methods make sense I still found it difficult to read.

Taking advantage of the more readable tests, I have created a custom XSLT which can be applied to the xUnit report.

With a bit of styling and bold text in the right place, the report can be extremely readable. When the above examples are executed and the transform has been applied, the report looks like this.

Screenshot

You can easily see which scenarios are passing, failing or pending while also taking advantage of the readable blocks of code to provide more context about what was executed.

This is just a prototype. It is only one possible syntax which you could use. As such, I would be really interested to hear your feedback on this. The framework is fully usable, the binaries can be downloaded here. If your interested in the actual implementation, all the code is available on GitHub. If you have any questions, then please contact me via twitter.

Leave a Reply

Your email address will not be published. Required fields are marked *