Sunday, 29 July 2012

Simple BDD

I have spoken before about how much I like the fluent-interface. I use it a lot expecially with object builders. I was looking at the Bddify framework. I have known about this style of testing and BDD for a while, but was really inspired about how Bddify write tests.

I realized that I could do this so easily with everyday tests as well without the need for any fancy frameworks etc. And just make my own tests easier to write and understand.

I was doing a very simple schedule for an import process and heeding the warning by Ayende about scheduling. I tried to consider the wise words and established that my requirement is very simple and to the point and most of these won't be a problem for me. With this in mind I wanted to make sure there are no bugs in the schedule logic so this is what I came up with. First I could express my requirements in the test:

[TestMethod]
public void SheduleShouldRunIfTimeIsGreater()
{
this
.GivenCountingController()
.GivenNewScheduler()
.WhenScheduleTimeIs(DateTime.Parse("23:00"))
.WhenCurrentTimeIs(DateTime.Parse("23:00"))
.ThenSheduleShouldRun()
.ThenSheduleShouldNotRunAgain()
.WhenCurrentTimeIs(DateTimeHelper.StartOfDay(DateTime.Now).AddDays(2))
.ThenSheduleShouldRun()
.ThenSheduleShouldNotRunAgain();
}
[TestMethod]
public void SheduleShouldNotRunIfTimeIsLess()
{
this
.GivenCountingController()
.GivenNewScheduler()
.WhenScheduleTimeIs(DateTime.Parse("23:00"))
.WhenCurrentTimeIs(DateTimeHelper.StartOfDay(DateTime.Now).AddHours(10))
.ThenSheduleShouldNotRun();
}
view raw Tests.cs hosted with ❤ by GitHub

The implementation of this is very simple and I have just done so directly in my test class. It's just about the grammar Given a set of inputs When certain conditions are met, Then we can expect a specific result.

  • Given - Construction of the objects I am testing.
  • When - Setting some criterea on the objects I have created.
  • Then - Run a method and (Act and Assert)
public SchedulerTests GivenCountingController()
{
var controller = new Mock<IImportController>();
_Count = 0;
controller.Setup(c => c.Run()).Callback(() =>
{
_Count++;
});
this._Controller = controller;
return this;
}
view raw Given.cs hosted with ❤ by GitHub
public SchedulerTests WhenScheduleTimeIs(DateTime dateTime)
{
_Configuration.Setup(c => c.ScheduledTime).Returns(dateTime);
return this;
}
view raw When.cs hosted with ❤ by GitHub
public SchedulerTests ThenSheduleShouldNotRun()
{
int count = _Count;
Assert.IsTrue(CountScheduleRunTimes() == count, "Expected the schedule should not have run");
return this;
}
view raw Then.cs hosted with ❤ by GitHub

Obviously to have a good grammar you first need to understand a bit more about your domain and tests. And what you will be testing, so when starting I still write the first test or 2 using a few variables and seeing how the test logic fits together and create my grammar from there.

Bugs with these kinds of things could be a nightmare in a live environment. So this style of testing helps you build all of the scenarios that you can think of and make sure those work through the lifetime of the solution.

No comments:

Post a Comment