Tuesday, August 19, 2014

Testing Wars

I am sitting in the back of the room during the last four weeks of a really intense twelve-week Java boot-camp, and this is the third time this question has come up: "if I make private methods how do I test them?" Encountering it once every two months is not bad, because it is a really, really good question.

There are two distinct camps at war over this issue: one says "private is private and we only test the side-effects," and the other says "you must test the private methods or you cannot not know which one fails." So what should you do? To quote a former student Dennis who answered most of my questions this way: "it depends!"

So I will paraphrase in my own words what my friend Susan answers when the question comes up. "It depends!" Really, there are good things to say about the position of both groups.

The group that insists on private being private is the more technically correct of the two groups. A unit test stands in for the client in the relationship with the class being tested. All that it really needs to test is that when a method is called it sees expected results. That could be a value returned, or it could be that the state of the tested unit or something else has changed. Technically, if for the given input the desired output is achieved then the test passed. If the desired output is not achieved, the test failed. But why did it fail?

That question is the heart of the argument presented by the second camp. They feel that if every method is tested individually, even the private ones, then we know precisely where a failure occurs. That really has to include private fields too, when we are testing the results of a private (or public) method that is supposed to change the state of the object being tested.

How can we accomplish this? In Java environments we typically place the unit test in the same package as the unit being tested and make the things to test accessible at the package level. In .NET the tests should be in a separate project and we need to grant assembly level access from the assembly containing the unit being tested to the assembly containing the tests.

So what camp to you belong too? Why not tear down some fences? I personally try to write all my tests so that private is private and test the side effects. When you expose something for a test, you are really exposing it to other code besides the test and relying on "good programmers" not to touch it. And I am a strong proponent of not having an excessive number of methods in a call chain, at least internally in a class. So if something fails I should not have too far to look, and do not forget this is what the debugger was designed for as well. But, in some circumstances I can certainly see the benefit of having tests on some of the private stuff, especially if what we are watching is prone to failure whenever we make a change. So I bend a little and allow it!

No comments:

Post a Comment