Yet another way to do BDD

Recently I was lucky enough to see talks by Ian Cooper (@icooper) and Rob Ashton (@robashton) where I had my eyes opened wide where BDD is concerned. The main things I took away were a new idea of what I should be testing, and a definite change to what I should be testing it with.

If you are interested in BDD, no doubt you will have encountered Specflow. It allows you to write in a human language, about what the expected behaviour of a piece of software is. This is what usually encourages development teams to use it. The promise that users, customer, mere mortals, will be able to write down what they want the software to do.

Jump forward in time, a month or so, and you might have had a couple of try outs with someone from the business. They will have loved it, and come away making noises to the effect that it is going to be easy to specify the behaviour of the system. Everybody is thrilled with the new confidence that they have. So early in the project too.

As you get further in though, the business is getting fed up with jumping through the, “Given, when, then,” hoops. It is at that point that you have to be honest about who the human readable test scripts are really for.

Specflow is a brilliant tool, and is a massive leap forward in terms of testing. It is definitely a good thing to be able to describe your software’s features using scenarios, and Given, When, Then, is a great way to describe behaviour. It’s just that sometimes, I wish that the lines of human readable stuff had a better connection to the code behind that is actually exercising your software. The human readable bit is really just there so that you can establish that your software is as described to the customer. So it’s best that we don’t lose too much time writing acceptance tests, or worse still maintaining them.

Just suppose that I could actually write unit tests, but have them go through a scenario. “What? That is not a unit test,” I hear you say. Well if you think about the outer surface of the software under test. The methods that you call are units. You are then testing behaviour and not implementation, which I am learning, is a great way to stop the test suite getting brittle. Sure you can still go all Uncle Bob on things if you’re trying to drive out design. In all honesty though, a lot of those tests are just going to be a cost in the long term.

One of the things I’ve been trying is to get a good way of running though scenarios that exercise a web front end, either a page or an API. I wanted to be able to get the same type of user acceptance test that I can achieve with Specflow, but to be able to step from the test script to the actual running context at design time or runtime.

To sort this out I’ve been using a library which I’ve made available on Nuget called NaughtyStep. It allows me to write unit tests that step through a scenario, and write to the console in a similar way to the output of a successful Specflow test. Although I prefer to use the Should library for asserts, I am using NUnit to give me some hooks so that I can run the tests in ReSharper. It works out quite well, because I can use test cases to test out scenarios with different values. Here’s an example of the sort of test you can write;


[TestFixture]
public class BddExample : NaughtyStepCoypuFeature
{
[TestFixtureSetUp]
public new void Init()
{
base.Init();
}

[TestFixtureTearDown]

public new void Dispose()
{
base.Dispose();
}

[Test]

public void VisitSite()
{
Scenario("Visit the home page", () =>
{
Given("a user visits the site", () => Context.VisitHomePage());
When("a user visits the site", () => Context.ClickSomething());
And("a user visits the site", () => Context.ClickSomethingElse());
Then("The title of the page should be", () =>
Context.CheckTitle().Should().Equal("Tuganet - making great development projects"));
});
}
}

The test needs a context to run. This sets up a headless browser using Coypu, and sees to the disposal of it afterwards,


public class SiteVisitor : NaughtyStepCoypuContext
{

public void VisitHomePage()
{
Browser.Visit(“http://localhost:53694/Index.html”);
Browser.Location.AbsoluteUri.Should().Equal(“http://localhost:53694/Index.html”);
}

public string ClickSomething()
{
//Your code here
}

public string ClickSomethingElse()
{
//Your code here
}
public string CheckTitle()
{
return Browser.Title;
}
}

These tests run up really well from the ReSharper test runner, and the feedback is as good as the text you place in the step arguments. You don’t need to use NUnit to run the tests though. You could write a console application, which calls out to classes that inherit a NaughtyStep base class, and see your software being exercised that way.

I’m planning to do some more posts to discuss other ways to work with NaughtyStep and produce what I think are really useful tests, which are easy enough to run up in CI builds without much modification. If you have any suggestions, the project site is probably the best way to get in touch, and it would be great to hear any feedback that you have.