Reputation: 802
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
Reputation: 136643
Problem as I see it: Avoid repeating common tests to validate n derivations of a common base type.
Upvotes: 1
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
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