Yes I do test private functions, because although they are tested by your public methods, it is nice in TDD (Test Driven Design) to test the smallest part of the application. But private functions are not accessible when you are in your test unit class. Here's what we do to test our private methods.
Why do we have private methods?
Private functions mainly exists in our class because we want to create readable code in our public methods.
We do not want the user of this class to call these methods directly, but through our public methods. Also, we do not want change their behavior when extending the class (in case of protected), hence it's a private.
When we code, we use test-driven-design (TDD). This means that sometimes we stumble on a piece of functionality that is private and want to test. Private functions are not testable in phpUnit, because we cannot access them in the Test class (they are private).
We think here are 3 solutions:
1. You can test your privates through your public methods
Advantages
- Straightforward unit testing (no 'hacks' needed)
Disadvantages
- Programmer needs to understand the public method, while he only wants to test the private method
- You are not testing the smallest testable part of the application
2. If the private is so important, then maybe it is a codesmell to create a new separate class for it
Advantages
- You can refactor this to a new class, because if it is that
important, other classes may need it too
- The testable unit is now a public method, so testable
Disadvantages
- You dont want to create a class if it is not needed, and only used by
the class where the method is coming from
- Potential performance loss because of added overhead
3. Change the access modifier to (final) protected
Advantages
- You are testing the smallest testable part of the application. When
using final protected, the function will not be overridable (just
like a private)
- No performance loss
- No extra overhead
Disadvantages
- You are changing a private access to protected, which means it's
accessible by it's children
- You still need a Mock class in your test class to use it
Example
class Detective {
public function investigate() {}
private function sleepWithSuspect($suspect) {}
}
Altered version:
class Detective {
public function investigate() {}
final protected function sleepWithSuspect($suspect) {}
}
In Test class:
class Mock_Detective extends Detective {
public test_sleepWithSuspect($suspect)
{
//this is now accessible, but still not overridable!
$this->sleepWithSuspect($suspect);
}
}
So our test unit can now call test_sleepWithSuspect to test our former private function.