Assuming I have the following (over-simplified) class structure:
class Base
{
public:
Base(int valueForFoo) : foo(valueForFoo) { };
virtual ~Base() = 0;
int doThings() { return foo; };
int doOtherThings() { return 42; };
protected:
int foo;
}
class BarDerived : public Base
{
public:
BarDerived() : Base(12) { };
~BarDerived() { };
int doBarThings() { return foo + 1; };
}
class BazDerived : public Base
{
public:
BazDerived() : Base(25) { };
~BazDerived() { };
int doBazThings() { return 2 * foo; };
}
As you can see, the doThings
function in the Base class returns different results in each Derived class due to the different values of foo
, while the doOtherThings
function behaves identically across all classes.
When I wish to implement unit tests for these classes, the handling of doThings
, doBarThings
/ doBazThings
is clear to me – they need to be covered for each derived class. But how should doOtherThings
be handled? Is it good practice to essentially duplicate the test case in both derived classes? The issue becomes worse if there are half a dozen functions like doOtherThings
, and more Derived classes.
Best Answer
In your tests for
BarDerived
you want to prove that all (public) methods ofBarDerived
work correctly (for the situations you have tested). Similarly forBazDerived
.The fact that some of the methods are implemented in a base class does not change this testing goal for
BarDerived
andBazDerived
. That leads to the conclusion thatBase::doOtherThings
should be tested both in the context ofBarDerived
andBazDerived
and that you get very similar tests for that function.The advantage of testing
doOtherThings
for each derived class is that if the requirements forBarDerived
change such thatBarDerived::doOtherThings
must return 24, then the test failure in theBazDerived
testcase tells you that you might be breaking the requirements of another class.