Tito
Tito

Reputation: 802

Unit testing different class hierarchies

What would be the best approach to make unit tests that consider different class hierarchies, like:

I have a base class Car and another base class Animal.

Car have the derived classes VolksWagen and Ford. Animal have the derived classes Dog and Cat.

How would you develop test that decide at run-time what kind of object are you going to use. What is the best approach to implement these kind of tests without using code replication, considering that these tests will be applied for milions of objects from different hierarchies ?

This was an interview question asked to a friend of mine.

Upvotes: 4

Views: 847

Answers (3)

Gishu
Gishu

Reputation: 136643

Problem as I see it: Avoid repeating common tests to validate n derivations of a common base type.

  • Create an abstract test fixture. Here you write the tests against the base type & in a abstract base class (search term 'abstract test fixture') with a abstract method GetTestSubject(). Derivations of this type override the method to return an instance of the type to be tested. So you'd need to write N subtypes with a single overridden method but your tests would be written once.
  • Some unit testing frameworks like NUnit support 'parameterized tests' (search term) - where you have to implement a method/property which would return all the objects that the tests need to be run against. It would then run one/all tests against each such object at run time. This way you don't need to write N derivations - just one method.

Upvotes: 1

amirhosseinab
amirhosseinab

Reputation: 1050

Actually Unit Test refers to Method Test, when you want to write a unit test you must think to the functionality of a method that you want to write and test, and then create class(es) and method(s) for testing that. by considering this approach when you design and write your code, maybe create hierarchies of classes or just single class or any type of other designs.

but when you have to use existing design like something you mentioned above, then the best practice is to use Interfaces or Base Classes for dependecy objects, because in this way you can mock or stub those classes easily.

Upvotes: 0

Eric Galluzzo
Eric Galluzzo

Reputation: 3241

Here is one approach that I've used before (well, a variant of this).

Let's assume that you have some sort of common method (go) on Car that you want to test for all classes, and some specific method (breakDown) that has different behavior in the subclass, thus:

public class Car {
    protected String engineNoise = null;

    public void go() {
        engineNoise = "vroom";
    }

    public void breakDown() {
        engineNoise = null;
    }

    public String getEngineNoise() {
        return engineNoise;
    }
}

public class Volkswagen extends Car {
    public void breakDown() {
        throw new UnsupportedOperationException();
    }
}

Then you could define a test as follows:

public abstract class CarTest<T extends Car> {
    T car;

    @Before
    public void setUp() {
        car = createCar();
    }

    @Test
    public void testVroom() {
        car.go();
        assertThat( car.getEngineNoise(), is( "vroom" ) );
    }

    @Test
    public void testBreakDown() {
        car.breakDown();
        assertThat( car.getEngineNoise(), is( null ) );
    }

    protected abstract T createCar();
}

Now, since Volkswagen needs to do something different in the testBreakDown method -- and may possibly have other methods that need testing -- then you could use the following VolkswagenTest.

public class VolkswagenTest extends CarTest<Volkswagen> {
    @Test(expected = UnsupportedOperationException.class)
    public void testBreakdown() {
        car.breakDown();
    }

    protected Volkswagen createCar() {
        return new Volkswagen();
    }
}

Hope that helps!

Upvotes: 0

Related Questions