Mark Needham

Thoughts on Software Development

TDD: Testing with generic abstract classes

with 8 comments

In a post I wrote earlier in the week I described a dilemma we were having testing some code which made use of abstract classes and Perryn Fowler, Liz Keogh and Pat Maddox pointed out that a useful approach for this problem would be to make use of an abstract test class.

The idea here is that we create an equivalent hierarchy to our production code for our tests which in the example that I provided would mean that we have roughly the following setup:

public abstract class ParentModelTest
{
}
 
public class BusinessProcess1ModelTest : ParentModelTest { }
public class BusinessProcess2ModelTest : ParentModelTest { }
public class BusinessProcess3ModelTest : ParentModelTest { }

We then want to create an abstract method on the ‘ParentModelTest’ class to create the object under test and we’ll implement this method in the sub classes.

We can then put the common tests into the abstract class and they will be run when we run the tests for each of the sub class tests.

My colleague Matt Dunn and I were looking at how you would implement this and he pointed out that it provided quite a nice opportunity to use generics to achieve our goal.

If we make the abstract test class take in generic parameters then it allows us to create our specific type in the ‘create’ method rather than having to create ‘ParentModel’ and then casting that for our specific sub class tests.

public abstract class ParentModelTest<T> where T : ParentModel
{
	protected abstract T CreateModel();	
 
	[Test]
	public void ShouldTestThoseCommonDependencies()
	{
		var model = CreateModel();
		// Do some awesome testing that's common across all 3 sub classes here
	}
}
[TestFixture]
public class BusinessProcessModel1Test : ParentModelTest<BusinessProcessModel1>
{
	protected override BusinessProcessModel1 CreateModel()
	{
		return new BusinessProcessModel1(...);
	}
 
	[Test]
	public void ShouldDoSomeEquallyOutstandingStuff() 
	{
		var model = CreateModel();
		// and test away
	}
}

It seems to work quite well and we realised that it’s actually a pattern that we had also used to test that our controllers would actually be injected with all their dependencies from our DI container or whether we have forgotten to register some of them.

We have an abstract class similar to this which all our controller tests extend:

public abstract class ContainerTest<T> where T : Controller
{
	[Test]
	public void ShouldHookUpAllDependencies()
	{
		var container = CreateTheContainer();
 
		var controller = container.Resolve<T>();
 
		Assert.IsNotNull(controller);
	}
}
public class AwesomeControllerTest : ContainerTest<AwesomeController> { }

When we haven’t got all the dependencies injected correctly the code will actually blow up on the resolve step so the last line is not strictly necessary but the test seems like it’s not testing anything at first glance without it.

Be Sociable, Share!

Written by Mark Needham

September 18th, 2009 at 12:40 am

Posted in Testing

Tagged with

  • The idea of an abstract test class is also explored by @jbrains on his presentation “Integration Tests are a Scam”, although for a different purpose. But it’s interesting to see more discussions about good test design. We tend to forget that test code is code too 🙂

  • Pingback: Tweets that mention TDD: Testing with generic abstract classes at Mark Needham -- Topsy.com()

  • @Danilo – Yeah I watched some of that presentation – really liked it – but I need to watch it again cause I don’t think I quite got all the ideas he was promoting!

    I don’t think I quite have the mindset of test code as being the same as production code. I try to write my test code to be readable to the next person who comes across it but I don’t yet refactor that code with the same regularity as I would if I came across messy production code.

    I’m working on that! 😀

  • Pingback: Reflective Perspective - Chris Alcock » The Morning Brew #436()

  • Pingback: DotNetShoutout()

  • By creating the abstract test it’s not that you are duplicating the same structure of the production code (although you end up with that, it’s not the end goal). The idea is to write tests that define the shared behaviour between all the subclasses. It’s a way to guarantee that the Liskov Substitution Principle will be followed by subclasses. It works for interfaces just as well (or mixins, if you’re in Ruby). You don’t want to re-test the behaviour everywhere (poor test-code duplication, although readable on a test-level), but you want to guarantee that the subclass behaves as expected. I think this would be a good post about when it’s good and bad to have duplication on test code 😀

  • Nice post. Think this is a good case for contract tests. You can have tests which should test the common behaviour in the contract test which you can mix with each of subclass test. Was thinking about it when I was reading your previous post but I thought I was too much influenced by JB’s talk at that time and so was driven to suggest it as a solution. Happy to know that I was indeed on the right track… 🙂

  • This looks like contract tests to me. As long as you’re using these abstract tests to verify common behavior and not to reuse test helpers, that makes me happy indeed. Rock on!