Indirect Tests

Given these classes: If you want to make sure that "Quadruped" is an animal with four legs, you can either a) put a UnitTest in the Quadruped tests, or b) UnitTests for Dog and Cat have "assertEquals(4, animal.legCount());" (Indirect Testing).

I'm pretty sure IndirectTests are a CodeSmell, though.

Actually, shouldn't this be a TestSmell? ?

When extracting a superclass, you might find yourself tempted to just say, "Oh, there are IndirectTests, I don't have to explicitly write tests for this superclass." It's probably a good idea to resist the temptation, though, and go ahead and move the tests up the tree.

Duplication in tests is still subject to the disadvantages of breaking the OnceAndOnlyOnce rule.

(Maybe there's a better name for this page - feel free to rename if you think of one. I just wanted to get something started.)

I ran into a similar problem recently. I wish there were a way to say "run this test class with the following subclasses of such-and-such a superclass" - sounds like a job for a *Unit hacker. Then you could have QuadrupedTest? that gets run with each of the subclasses of Quadruped replacing the class Quadruped in QuadrupedTest?. Does this make sense? -- IainLowe

I'm guessing that you don't want to write ANY code for the subclass test cases. Otherwise, all you need is a template method in you top testclass. --JeanPhilippeBelanger

Correct. I'm not talking about testing inherited functionality but about testing overridden functionality without having to push down the tests into the test cases for the subclasses. Obviously if I have been refactoring correctly I have a base class that has all the common functionality. I still need to check that each subclass hasn't broken the contract of the base class while still respecting the interface. For example if I have a base class method that takes a File object and writes to it and my subclass deletes the File I would like to have the test case fail. Of course this may be a slippery slope towards LiskovWingSubtyping or LiskovSubstitutionPrinciple. Hrmm... -- il

Hrmm... the right way requires writing some code - the base class tests, rather than creating the object they test themselves, call a method or a factory to create the object. Then your subclasses can simply replace that method or factory with one that replaces the object to be tested with an instance of themselves.

    class TestAnimal?:
        def getAnimal()
            return new Animal()
        def testEat()
            a = getAnimal()

class TestCat?(TestAnimal?) def getAnimal() return new Cat()

Three lines counts as ANY code, I suppose, but that's probably the best I can manage without some variation or CopyAndPasteProgramming or a preprocessor phase:

    foreach %T (Dog,Cat) do cpp /P TestAnimal?.py /DAnimal=%T > python

Bleah - I think I need to take a bath.

Generally, I think you want your UnitTests to be independent of your implementation details. Which is to say, if we start with Cat and Dog, with independent tests for each, and smell redundancy, my gut feeling is that the commonalities of Cat and Dog get lifted into a base class, and the commonalities of the tests get lifted into a base class, but the test baseclass won't worry at all about the existence of the animal base class, and vice versa.

Test code should be written OnceAndOnlyOnce, but it isn't at all clear that it should be run only once.

Surely it should run when and wherever it can provide some benefit or support?

I have had problems with AbstractTests? in JavaUnit, which I believe to be a subset of IndirectTests. The TestRunner tries to run them, meaning of course instantiating and calling methods upon this abstract class. Poof! Red bar.

My solution was to hack whichever test runner I was using. Really ought to send that upstream.

I've read something else on here about this, in relation to "ensuring API contract is met". I think the example was of Collection implementations which didn't. [I forget the WikiName. Please AnswerMe if you can] -- MatthewAstley

Not to be confused with SuperTest

View edit of November 24, 2005 or FindPage with title or text search