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
Showing posts with label TDD. Show all posts
Showing posts with label TDD. Show all posts
Saturday, April 23, 2011
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.
Tuesday, April 20, 2010
Thoughts on Testing
I drew a picture with Balsamiq. Which is great. These are my current thoughts on testing.
Consider this blog part II of my SEO unfriendly series.
Friday, March 05, 2010
The case of the missing assert
I was looking at a friend of mines code late last night and he was writing his tests in MSTest. The test he wrote was an expected exception test.
Option 1 Attribute and fail.
Option 2 No Attribute try catch
You can call the Assert.IsTrue(True);
[TestMethod]
[ExpectedException(typeof(SomeException))]
public void CanDoSomething_WithSomeThingThatThrows_ReturnsTrue()
{
var something = SomeFactory.GetSomething();
something.DoSomething(x => { throw new NotImplementedException(); });
var result = something.DoSomethingElse<ISomeThingElse>();
Assert.IsTrue(true);
}
I was tired, it was late, I'm used to a using different test framework but I got in contact straight away.....spotted something in your codez. You're Assert is true everytime.Of course dear reader you will have spotted the ExpectedException attribute as you, unlike me are not an idiot but my eyes see:
[TEST BLAH]
[yes i didn't spot the attrib here]
public void STUFF_I_WILL_READ_IF_TEST_IS_NOT_OBVIOUS()
{
//SOME ARRANGING STUFF
..blah
//THIS IS IMPORTANT
var result = something.DoSomethingElse<ISomeThingElse>();
//AND SO IS THIS
Assert.IsTrue(true);
}
In my semi-comatosed state my eyes fix on Assert.IsTrue(true) and I can look away from it. I'm used to NUnit's (and xUnit and mbUnit) Assert.Throws [TEST BLAH]
public void STUFF_I_WILL_READ_IF_TEST_IS_NOT_OBVIOUS()
{
//SOME ARRANGING STUFF
..blah
//THIS IS IMPORTANT
Assert.Throws(()=> something.DoSomethingElse<ISomeThingElse>());
}
However some frameworks don't support this. So you've got 2 options.Option 1 Attribute and fail.
[TestMethod]
[ExpectedException(typeof(SomeException))]
public void CanDoSomething_WithSomeThingThatThrows_ReturnsTrue()
{
var something = SomeFactory.GetSomething();
something.DoSomething(x => { throw new NotImplementedException(); });
var result = something.DoSomethingElse<ISomeThingElse>();
Assert.Fail();
}
As my eyes always look the assert and so if I see a fail. I'll look to see why.Option 2 No Attribute try catch
[TestMethod]
public void CanDoSomething_WithSomeThingThatThrows_ReturnsTrue()
{
var something = SomeFactory.GetSomething();
something.DoSomething(x => { throw new NotImplementedException(); });
try
{
var result = something.DoSomethingElse<ISomeThingElse>();
Assert.Fail();
}
catch (SomeException)
{
Assert.IsTrue(true);
}
catch (Exception)
{
Assert.Fail();
}
}
And what happens when we want to invoke an action that doesn't expect anything. That you just want to run to see if doesn't fail. Well you've got Assert.DoesNotThrow in most .Net unit testing frameworks.You can call the Assert.IsTrue(True);
[TestMethod]
public void CanDoSomething_WithSomeThingThatDoesnotThrow()
{
var something = SomeFactory.GetSomething();
something.DoSomething(x => { throw new NotImplementedException(); });
Assert.IsTrue(True);
}
Or just drop the assert. [TestMethod]
public void CanDoSomething_WithSomeThingThatDoesnotThrow()
{
var something = SomeFactory.GetSomething();
something.DoSomething(x => { throw new NotImplementedException(); });
}
So with MStest you can't use Assert.Throws but you do have options. Mine is to use another framework ;)
Monday, October 26, 2009
Remote Pairing - a quick guide
Today I spent most of the most of my morning and afternoon honing my TDD skills with Rob Cooper. Whilst none of the work we did was particularly earth-shattering it was great to delve in code and discuss at length. We tackled a TDD Kata in depth rather than discussing the 'form' elements we concentrated on discussing how the design emerged and the different approaches to testing. We had a few technical issues and ironed most of them out but I wanted to outline the setup as it seemed fairly easy to arrange.
Remote Pair Recipe
- IDE of choice - (helps if these match)
- Git - (or other DVCS)
- GitHub Account - (or other hosted service)
- Skype/GTalk/Live Messenger - for Audio Comms
- MS SharedView - see what the other pair is doing
MS SharedView deserves a special mention here as it worked extremely well for screen sharing.
Guidelines
Check your setup
Before starting make sure you can both access and commit to Github. This is the place where you are both going to be passing your code back forth to. Make sure your equipment works (someone in this pair had a crappy mic in his headset - no names mentioned (*cough* - me)). This slowed us down and upset flow a little. Thankfully the other pair was not blameless. If you are going to use other tools agree what they are, including version, before the event so you don't have to spend time scrabbling around the internet for requisite software.Have a plan
Do not go into a session unprepared. Without a plan a session will lose direction. I think we were over-prepared with things to do but its better to have more than less.Don't be scared
Having someone watching your every keystroke may seem like a daunting thing butDon't be offensive either
There are many ways to convey that your pair has not removed the duplication in that class other than by comparing his intellect to that of an amoeba. Pick a nicer one.Swap driver-navigator often
Rob and I swapped mid-scenario in our TDD session. I would red-green (to the simplest possible case) then Rob would grab the session add a further test and refactor. We thought this was a nice way of doing things as we both had our input in creating the feature. I would make the fixture and pass it over to Rob as tested. Rob double checks with a further scenario and makes the call to refactor.Embrace your differences
Rob and I had a slight difference in our approach to testing. We stopped and talked about it afterwards but it was not a problem in this case as the code was 'throw away'. The issue may have been more pressed if we wanted to keep the code.Take breaks
I'm ashamed to say that even though Rob and I are both Pomodoro Technique practitioners we took 1 break in the multi-hour session. This was wrong. I found that towards the end of the session I was losing concentration. With pairs I think this especially important due to the intense focus you have with two of you.Workflow
We approached the exercise like so:- Driver picks feature
- Driver writes test.
- Driver passes test.
- Driver commits and pushes to GitHub
- Navigator pulls from github
- Navigator becomes Driver
- Driver adds 'confidence' test and refactors.
- Go to 1.
Tuesday, August 25, 2009
Selling my soul for a free TDD course?
I just read this on a blog I follow and normally I wouldn't do this but I really want to go on this course... so for that reason here bbits have a peace of my integrity. Oh and one more thing... #Moonfruit.
P.S. Roy did a great videocast of reviewing the tests for NerdDinner. You should check it out:
http://weblogs.asp.net/rosherove/archive/2009/03/20/test-review-1-nerddinner.aspx
Roy Osherove is giving an hands-on TDD Masterclass in the UK, September 21-25. Roy is author of "The Art of Unit Testing" (http://www.artofunittesting.com/), a leading tdd & unit testing book; he maintains a blog at http://iserializable.com (which amoung other things has critiqued tests written by Microsoft for asp.net MVC - check out the testreviews category) and has recently been on the Scott Hanselman podcast (http://bit.ly/psgYO) where he educated Scott on best practices in Unit Testing techniques. For a further insight into Roy's style, be sure to also check out Roy's talk at the recent Norwegian Developer's Conference (http://bit.ly/NuJVa).
Full Details here: http://bbits.co.uk/tddmasterclass
bbits are holding a raffle for a free ticket for the event. To be eligible to win the ticket (worth £2395!) you MUST paste this text, including all links, into your blog and email Ian@bbits.co.uk with the url to the blog entry. The draw will be made on September 1st and the winner informed by email and on bbits.co.uk/blog
P.S. Roy did a great videocast of reviewing the tests for NerdDinner. You should check it out:
http://weblogs.asp.net/rosherove/archive/2009/03/20/test-review-1-nerddinner.aspx
Subscribe to:
Posts (Atom)

