In which I show how best to test an abstract class, which normally wouldn’t be instantiatable.
Abstract classes are not instantiatable, so how do you test one?
class Abstract { public: int common(); virtual int special() = 0; }; class Concrete : public Abstract { public: int special(); };
Say you want to test Abstract::common()
, like so:
TEST(TestAbstract, helper_returns42) { Abstract abs; //cannot declare variable ‘abs’ to be of abstract type ‘Abstract’ ASSERT_EQ(42, abs.common()); }
It’s not possible, because
is pure virtual (it has no implementation in common() special()Abstract
). So how do you test a class that cannot be instantiated? It can be tempting to test through a concrete subclass:
TEST(TestAbstract, common_returns42) { Concrete abs; ASSERT_EQ(42, abs.common()); }
But this is generally a bad idea, since Concrete
might change the behaviour of common()
. Even though it is not virtual, it operates under a different state. And even though you know it will work now, you don’t know how Concrete
will change in the future, and then you don’t want tests that don’t have anything to do with Concrete
to start failing. Also, creating a Concrete
object when you are testing on Abstract
is confusing to the reader.
Instead, I recommend you derive a class to be used just for testing:
class AbstractForTest : public Abstract { int special(); }; TEST(TestAbstract, common_returns42) { AbstractForTest abs; ASSERT_EQ(42, abs.common()); }
In this way you get rid of the unwanted dependency, and the test is easier to understand. As a final note, make sure you name your test-class something that clearly distinguishes it as a testing artifact, like I did above. Also make sure to keep it in your test code (e.g. TestAbstract.cpp), not in your production code (e.g. Abstract.h/.cpp).
Hi Anders,
When you say:
because common() is pure virtual (it has no implementation in Abstract)
I think you mean that “special” is pure virtual, correct?
Actually, now that I think about it, maybe the pure virtual specifier (=0) in the class definition belongs with the “common” member function in the base class instead of the “special” member function, since the rest of the post uses “common” and not special.
Hi Dan,
You are absolutely, right, I meant that
special()
is pure virtual, notcommon()
. Thanks!The pure virtual specifier does however belong where it is, on
special()
. The point is that I am trying to test a class that also has a pure virtual method, not the pure virtual method itself (which would be impossible, since it has no implementation). I have updated the post to make this more obvious.Hi Anders,
Thanks for the clarification. Looking forward to reading additional posts when you have time.
Glad you enjoy it! There will be another post this Friday quite similar to this. Watch this space! :)
RSS: https://blog.knatten.org/feed/
Twitter: http://twitter.com/#!/knatten
Do you ever read something about Google Mock? So please read it and refactor your “bad” solution.
I am a newbee, but there exists the posibility to have mocked classes. Why not use them instead?
Sure! You can use any kind of mocking framework for this instead.