Home :: News ::

Defeat in Detail: Unit tests and SpecsFor

13th, November 2011
For the new game I am creating I will be using Unit Tests extensively (unlike other project I have/am working on…cough) and with this many different methodologies follow just for testing code. When I come to create new code in the game I will be performing TDD (Test Driven Development) which means testing/creating test cases as you code and not as an afterthought. Currently I am using code I have created for a test app, and thus I am backtracking all missed unit tests – AND NO NEW CODE WILL BE WRITTEN until I have 100% (or as close to) coverage of public methods in my codebase.

To do this, I am using NUnit, MOQ via SpecsFor; SpecsFor is a free framework for testing methods using a Behaviour-Driven Development methodology (e.g. Given , When,  Then). There are many benefits I have found to using this structure so far:
  • Brilliant for understanding where a bug has occurred and what should happen (great for knowing what has changed)
  • A constant structure throughout all testing - this means all tests should be easy to follow once the structure is understood
  • Very descriptive and minimal - all test methods are kept as small as possible and only one test/assert per function
  • Reuse of constructors and manipulators - the plan is to create constructor and initial objects through the framework so they can be tested in many places
  • Encourages interfaces - without interfaces the mocking can be a pain and encourages interfacing at every opportunity
Also, SpecsFor automatically creates mock objects through StructureMap and means you can track how the current class is interfacing with other objects easily and in a standard.


"Wow, this all sounds great, but what are the drawbacks?" - the only drawback for SpecsFor is the learning curve, getting your head around what is happening can take a few moments (especially with the limited documentation on the website) but if you watch the following videos then you will start to understand. 

Here is an example of a test in my PathFindingInfo class; this class holds and processes the current target and step in path finding (step: where to move NOW and target: the final destination):

 
public class a_target_has_been_set : IContext
{
public void Initialize(ITestState state)
{
state.SUT = new PathfinderInfo();
state.SUT.SetTarget(new Vector2(100, 100));
}
}

[TestFixture]
[Given(typeof(a_target_has_been_set))]
public class when_target_has_been_reached : SpecsFor
{
public when_target_has_been_reached(Type[] context) : base(context) { }

protected override void When()
{
//Nothing to set
}

[Test]
public void then_should_not_be_ready_for_a_step()
{
Assert.IsFalse(SUT.IsReadyForNextStep(new Vector2(100f, 100f)));
}

[Test]
public void then_should_not_have_a_target()
{
SUT.IsReadyForNextStep(new Vector2(100f, 100f));
Assert.IsFalse(SUT.TargetPosition.HasValue);
}

[Test]
public void then_should_not_have_a_next_step()
{
SUT.IsReadyForNextStep(new Vector2(100f, 100f));
Assert.IsFalse(SUT.NextStep.HasValue);
}
}


This test reuses the [Given] class (a_target_has_been_set) on all of the [Test]s – this means we have fresh objects every time. Now, the best way to read these tests is via the names given, here is an example:
GIVEN a_target_has_been_set
WHEN when_target_has_been_reached
THEN then_should_not_be_ready_for_a_step

As you can see, each part that builds the test increases the descriptive structure of the inputs and outputs of the tests - VERY NICE :)

Once I have started playing with Mocks then I will post my findings, as for now I am unit testing all my existing code (thank god for re-usable code).

I would like to thank the creator of the SpecsFor system Matt Honeycutt for all brilliant work he has done and released online – please visit his blog for more info on this and much much more at http://trycatchfail.com/

0 Comments Posted by Simon Colmer

Comments:


No comments found
Add a comment
Name:
Email:
Comment:
Security:
X-Volt Studios, Copyright 2009. ©