I am looking for the cleanest way to write unit tests for Python private methods. I know that usually you don't want to test private methods, but we have inherited a gigantic behemoth of a Python file which we need to refactor into more maintainable modules.
We don't understand its logic, but we know it works, and so are looking to use TDD to ensure our refactoring does not break the code, and currently the 90% of the code is located in private methods and the module does too much to reliable test it all purely by black box testing.
I fully expect I'll write some tests that will get removed once the refactor is complete, but for now I'd like to be able to plug into some private methods to test them to increase my confidence that my refactor has not broken key logic as I transition to a more maintainable (and testable) layout.
To test private methods, you just need to test the public methods that call them. Call your public method and make assertions about the result or the state of the object. If the tests pass, you know your private methods are working correctly.
Unit Tests Should Only Test Public Methods The short answer is that you shouldn't test private methods directly, but only their effects on the public methods that call them. Unit tests are clients of the object under test, much like the other classes in the code that are dependent on the object.
Why We Shouldn't Test Private Methods. As a rule, the unit tests we write should only check our public methods contracts. Private methods are implementation details that the callers of our public methods are not aware of. Furthermore, changing our implementation details should not lead us to change our tests.
In Python, "private" methods are only a sign for developer that they should be private. In fact, you can access every method. When you start a method name with two underscores, Python does some name "magic" to make it harder to access. In fact, it does not enforce anything like other languages do.
Let’s say that we have the following class:
class Foo:
def __bar(self, arg):
print(arg)
def baz(self, arg):
self.__bar(arg)
To access the "private" __bar method, try this:
f = Foo()
f._Foo__bar('a')
More about identifiers could be found in the documentation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With