views:

96

answers:

3

Imagine a system of filters (maybe audio filters, or text stream filters).

A Filter base class has a do_filter() method, which takes some input, modifies it (perhaps), and returns that as output.

Several subclasses exist, built with TDD, and each has a set of tests which test them in isolation.

Along comes a composite class, of an unrelated type Widget, which has two members of different Filter types (a and b), which deal with quite different input - that is, certain input which would be modified by filter a is passed through unmodified by filter b, and vice versa. Its process_data() method calls each filter member's do_filter().

While developing the composite class, there emerge tests that check the assumption that Widget's filters aren't both processing the same data.

The problem is, these sort of tests look identical to the individual filter's test. Although there might be other tests, which test input which should be modified by both filters, many of the tests could almost be copied and pasted from each of the filter's tests, with only small modifications needed to have them test with Widget (such as calling process_data()), but the input data and the assert checks are identical.

This duplication smells pretty bad. But it seems right to want to test the components' interactions. What sort of options will avoid this sort of duplication?

+1  A: 

I fairly frequently extract test-logic to separate classes, so I'd extract the filter test to a separate class that is essentially not a unit test by itself. Especially if your test classes are physically separated from your production code this is really a decent way to solve this problem (i.e. No-one will think it is production code since it's in the test space)

krosenvold
+1  A: 

I asked something similar about a abstract base class and unit testing here, it has some interesting points that you might find useful.

http://stackoverflow.com/questions/243274/best-practice-unit-testing-abstract-classes

Paul Whelan
+3  A: 

Within one Test suite/class have a method

public void TestForFooBehaviour(IFilter filter) 
{
    /* whatever you would normally have in a test method */
}

Then invoke this method from both the original test on the simple filter as well as from the composite filter. This also works for abstract base classes. Obviously FooBehaviour should be a meaningful description of the aspect of filters you are testing. Do this for each behaviour you want to test.

If you language supports duck typing or generics feel free to use it if it helps.

ShuggyCoUk