Whilst writing up some notes I keep on changing between tests that cover something (as in test coverage) and tests that specify behaviour. It strikes me that these two concepts are orthogonal to one another. The former is an after thought, something that aids regression, the latter a pre-requisite to writing the code.
The funny thing is that I hear about test coverage but we never talk about specification coverage.
Saturday, April 23, 2011
TDD for abstract classes
I don't seem to use abstract classes much anymore. The tendency is for me to prefer interfaces over abstract classes as I've been inculcated with mantra 'composition over inheritance'. Where common behaviour is observed though it just feels natural to shove that behaviour in , I dunno, something like a superclass.
I like the template pattern too. So I do use abstract classes occasionally.
Concerning testing I have tended to duplicate testing this behaviour in the past. This is something that has not settled well. Duplication in testing may be slightly less repugnant than duplication in production code but there must be a valid reason.
How should we tackle testing abstract methods then?
Here are a couple of strategies.
Firstly here is my class
An abstract test class
We can put the tests for the behaviour into an abstract test class using a protected but uninitialised instance member. In our concrete sub class test class we inherit from the abstract test class and instantiate the sub class variable When we run the tests the superclass tests run with the subclasses.
If the subclass has more methods that need to be tested then a clumsy casting of the concrete type over the instance variable has to performed each time we test. Alternatively a separate member of the subclass needs to be setup as well the abstract one.
An mock of the abstract class
Alternatively we can use a mocking framework to mock the abstract class and run tests on that.
A fake concrete class
If the feeling of mocking an abstract class doesn't sit well an slight variation would be to create a fake concrete instance and perform the tests on that.
If I was using Mspec today I could has used its behaviours functionality which may have been more simple but I wanted to see from a TDD point of view what options I had.
Do you use any other strategies for testing abstract classes?
All the code if you want it
I like the template pattern too. So I do use abstract classes occasionally.
Concerning testing I have tended to duplicate testing this behaviour in the past. This is something that has not settled well. Duplication in testing may be slightly less repugnant than duplication in production code but there must be a valid reason.
How should we tackle testing abstract methods then?
Here are a couple of strategies.
Firstly here is my class
An abstract test class
We can put the tests for the behaviour into an abstract test class using a protected but uninitialised instance member. In our concrete sub class test class we inherit from the abstract test class and instantiate the sub class variable When we run the tests the superclass tests run with the subclasses.
If the subclass has more methods that need to be tested then a clumsy casting of the concrete type over the instance variable has to performed each time we test. Alternatively a separate member of the subclass needs to be setup as well the abstract one.
An mock of the abstract class
Alternatively we can use a mocking framework to mock the abstract class and run tests on that.
A fake concrete class
If the feeling of mocking an abstract class doesn't sit well an slight variation would be to create a fake concrete instance and perform the tests on that.
If I was using Mspec today I could has used its behaviours functionality which may have been more simple but I wanted to see from a TDD point of view what options I had.
Do you use any other strategies for testing abstract classes?
All the code if you want it
Friday, April 22, 2011
TDD Strategies
Just scribbling some notes thought this looked bloggable:
Test Driven-development can be approached using at least two strategies, a mock based approach or a state based approach (Martin Fowler calls this a classicist approach http://martinfowler.com/articles/mocksArentStubs.html). When presented with the initial idea, TDD seems simple; write the test to verify the behaviour code you are about to write. A common example of this is a calculator.
Say we have a calculator class that has the following method:
public void int Add(int integer1, int integer2)
We may write a test to verify this works first;
public void Should_Sum_inputs_together()
{
var result = new Calculator().Add(1,4);
Assert.AreEqual(5,result);
}
This is probably the defacto example of a state based testing approach. An action is performed on a class, and then its state is interrogated or a return value is verified. In many introductions to TDD you will find trivial examples such as this one. When test-driving code ‘in the wild’ you soon find that certain things become more complex very quickly.
Mock based TDD
Continuing on with the calculator example we can see where state based testing alone may not be enough.
Say we move a little closer to the GUI and have a ButtonInterface class that implements the interface,
IButtonInterface
{
Button Zero;
Button One;
…
Button Nine;
Button Add;
Button Equals;
void PressButton(Button button);
}
Our test may be :
public void Should_Sum_inputs_together()
{
//mock a calculator -- I’m using pseudo code based on Moq
var mock = new Mock();
ICalculator calc = mock.Object;
IButtonInterface calcUI = new ButtonInterface(calc);
calcUI.PressButton(this.One);
calcUI.PressButton(this.Add);
calcUI.PressButton(this.Four);
calcUI.PressButton(this.Equals);
mock.Verify(c => c.Add(1,4));
}
When testing the button interface we do not need to know how our class that does the addition manages the task. It is not the responsibility of the button interface to do so. However it is the responsibility to take the button inputs and send the appropriate messages to the calculator.
This is where mock based testing comes in. If the ICalculator interface hasn’t been written yet or perhaps there is a cost in setting up an ICalculator, for example it may be dependant on a filesystem or a database. In these cases tests may run slowly due to getting the dependancy into the correct state and then resetting it afterwards. In these examples and the more striking fact the the ButtonInterface doesn’t care all we need to verify is that the correct message has been sent to the correct interface.
Test Driven-development can be approached using at least two strategies, a mock based approach or a state based approach (Martin Fowler calls this a classicist approach http://martinfowler.com/articles/mocksArentStubs.html). When presented with the initial idea, TDD seems simple; write the test to verify the behaviour code you are about to write. A common example of this is a calculator.
Say we have a calculator class that has the following method:
public void int Add(int integer1, int integer2)
We may write a test to verify this works first;
public void Should_Sum_inputs_together()
{
var result = new Calculator().Add(1,4);
Assert.AreEqual(5,result);
}
This is probably the defacto example of a state based testing approach. An action is performed on a class, and then its state is interrogated or a return value is verified. In many introductions to TDD you will find trivial examples such as this one. When test-driving code ‘in the wild’ you soon find that certain things become more complex very quickly.
Mock based TDD
Continuing on with the calculator example we can see where state based testing alone may not be enough.
Say we move a little closer to the GUI and have a ButtonInterface class that implements the interface,
IButtonInterface
{
Button Zero;
Button One;
…
Button Nine;
Button Add;
Button Equals;
void PressButton(Button button);
}
Our test may be :
public void Should_Sum_inputs_together()
{
//mock a calculator -- I’m using pseudo code based on Moq
var mock = new Mock
ICalculator calc = mock.Object;
IButtonInterface calcUI = new ButtonInterface(calc);
calcUI.PressButton(this.One);
calcUI.PressButton(this.Add);
calcUI.PressButton(this.Four);
calcUI.PressButton(this.Equals);
mock.Verify(c => c.Add(1,4));
}
When testing the button interface we do not need to know how our class that does the addition manages the task. It is not the responsibility of the button interface to do so. However it is the responsibility to take the button inputs and send the appropriate messages to the calculator.
This is where mock based testing comes in. If the ICalculator interface hasn’t been written yet or perhaps there is a cost in setting up an ICalculator, for example it may be dependant on a filesystem or a database. In these cases tests may run slowly due to getting the dependancy into the correct state and then resetting it afterwards. In these examples and the more striking fact the the ButtonInterface doesn’t care all we need to verify is that the correct message has been sent to the correct interface.
Subscribe to:
Posts (Atom)