Reputation: 4014
I have an abstract class with some concrete and abstract protected methods, and I have a PHPUnit test for this abstract class.
Then I have classes that extend the abstract class and implement the abstract protected methods.
I'm curious of the smartest way to test that the child classes return what they need to return from the otherwise abstracted protected methods.
I have read a lot that you should not test private/protected methods, but I'm finding this awkward because to get code coverage across the protected method, I must replicate many of the tests from the abstract class test, which involves producing many mock objects and setting their methods to return specific values.
The end result will be a lot of tests that have very tight coupling to other classes. If I changes a class, the tests on for class need to change (totally ok), and then countless mock implementation of that class will need to change also.
At the end of the day, if the abstract class works, then I know my child object will work also, so long as it's implementation of the abstract protected methods returns an expected value.
So I'm wondering if I'm overlooking a pattern.
Duplicating tests across every child class doesn't seem to be better than testing that the child classes correctly implement their interfaces.
Upvotes: 2
Views: 646
Reputation: 43790
You are overlooking a pattern. It would be the Strategy Pattern. The protected methods of the child objects should be refactored into their own object with the protected method as a public method. You would then be able to test that these public methods return the correct thing.
Your tests for the base class would only need to change to have the mock object passed in. If your child classes are only implementing protected methods of the base abstract class. You can remove the abstract from the base class and have the children implement a strategy interface.
This will make your design more flexible. You would be able to easily extend the base class for other reasons and still have all of the previous functionality available to you.
Upvotes: 1