Should I unittest private/protected method
Solution 1
From a theoretical point of view, you only need to test public methods of your instantiable classes (in standard OOP languages). There is no point in testing the internal behaviour because all you want is "which output for that input" (for a particular method, or for the entire class). You should try to respect it as much as you can because it forces you to ask some questions about the encapsulation of your class and the provided interface which may be decisive for your architecture.
From a pragmatic point of view, you can sometimes have some abstract helper classes with no implemented concrete subclass or an abstract class factoring 90+% of its child classes and where it would be too hard to test the output without plugging into a protected method. In those kinds of cases, you can mock a subclass.
In your straightforward example, I would suggest you to only test the class Tiger
(and only the public method eat
).
Just a note for people thinking to TDD. In TDD, you shouldn't have started to code the class
Mammal
before the classTiger
becauseMammal
should be the result of a refactoring phase. So, you certainly woudn't have any specific test forMammal
.
Solution 2
The way I would approach this is:
- Create a minimal testable subclass of
Mammal
which provides minimal implementations of the two protected methods that allow you to unit test the behavior of the public methods. - Write separate unit tests for each subclass which again test the public methods on
Mammal
, but are asserting the behavior that is specific to that subclass.
This should give you the necessary testing coverage with a minimal number of tests.
One alternative approach would be to test the subclasses only, and on one of the subclass unit tests also assert the features specific to Mammal
. This avoids the need to create a specific testing subclass, however two disadvantages are:
- You are no longer testing
Mammal
in isolation, and therefore the tests on theMammal
specific code are susceptible to failing because of issues in the subclass. - It may be less obvious to others how and where the properties of
Mammal
are being tested.
Solution 3
When testing you should focus on the outside behaviour of your code, not on implementation details. I don't know the context, so I'll just make some huge assumptions here.
Do you really care about the behaviour of a (potentially abstract) Mammal superclass? Is the reuse-through-inheritance relationship that important? What if you decide to replace the inheritance relationship to a composition-based strategy?
I would focus on testing the behaviour of the classes you actually care about: "Does a Tiger eat as expected?" instead of testing some abstract superclass that is only introduced for code reuse.
Related videos on Youtube
Shiplu Mokaddim
I am, a learner, explorer. My blog is shiplu.mokadd.im #SOreadytohelp ###Some of my answers. Best way to find differences between two large arrays in PHP Detect if cookies are enabled in PHP Can I open socket in PHP from a specific IP (if the machine has two IPs)? Performance of copying a file with fread/fwrite to USB How to extract relative URL from argument values from request string? Capture image with imagegrabscreen and Wamp Would this be enough to deter a robot? If domain A has an iframe of domain B, which has an iframe of domain A, can domain A access the cookies of domain B? Can you use SELECT JOIN for questions and its tags? Splitting huge sql dump file in smallest chunks possible
Updated on June 13, 2022Comments
-
Shiplu Mokaddim almost 2 years
This is actually language agnostic. But I'll give you context in python.
I have this parent class
class Mammal(object): def __init__(self): """ do some work """ def eat(self, food): """Eat the food""" way_to_eat = self._eating_method() self._consume(food) def _eating_method(self): """Template method""" def _consume(self, food): """Template method"""
Here
eat
is the only public method whereas_consume
and_eating_method
are actually protected methods which will be implemented by child classes.What will you test when you have written only the
Mammal
class?Obviously all 4 methods.
Now let's introduce a child
class Tiger(Mammal): def _eating_method(self): """Template method""" def _consume(self, food): """Template method"""
Look at this class. It has only 2 protected methods.
Should I test all 4 methods of
Tiger
(including 2 inherited) or just test the changes introduced (only overrided 2 methods)?What is the ideal case?
-
Daniel over 9 yearsThat depends. Normally, the
eat
-method is tested with every possible outcome of_eating_method
and_consume
. So only the changed methods have to be tested.
-
-
Gnucki over 9 yearsYes, you can just test this method (the only one which is public).