Sunday, November 11, 2012

Week 11 - Private Testing (Nov. 5 to Nov. 11)


Another week gone. I'm glad to be done with the second test. The most recent project was pretty rough to get through as I had several projects due Monday, Tuesday and Wednesday evenings, in addition to the makeup test on Monday. Another thing which made this project somewhat difficult to get through is that I had implemented a more complex form of this same project in CS 315H a few years ago.

Fortunately, my partner Zesen was very accommodating of my schedule and we were able to complete the entire project without too many hangups.

I enjoyed the design component of this project. I would have expected that more of this course would involve designing classes and actually writing code in object oriented style, but the amount of experience I'm getting with C++ is also very valuable, even if it's not precisely what I thought I was signing up for.

My birthday is Tuesday, so I'm happy that this week is going to be relatively light for once.

---

I read a blog post about how unit testing private functions is supposedly evil. The primary argument seems to be that you shouldn't care about implementation details when testing, but I think that is a somewhat closed-minded approach. There are many algorithms that have a very simple public interface but which might contain relatively complex components in some implementations that should be tested individually. It could be rather difficult to know if the test of the public interface is getting good code coverage, or it may be extremely difficult to construct tests which adequately test the nested components. More likely, the algorithm is so complex that in order to make it readable, and thus maintainable, you would want to refactor the method into several utility functions. Sometimes refactoring makes sense because a number of public methods may have to handle the same functionality and thus refactoring private methods allows for code reuse, which is always a good thing.

About that latter point, the writer of the blog had stressed that if you find the need to refactor relatively complex behavior into private methods, why not refactor that same functionality to public methods in a helper class, so that the functionality can be tested in that way? I can't even think how to rebut that point except that the author seems to be missing the point. Some of these private methods might modify the state of the object directly, and do so in such a way that calling these functions without executing any other part of the algorithm might leave the object in a bad state, or a state which doesn't make sense from any external interface.

So yes, I agree that unit testing functions which are not part of a public interface will break encapsulation, but it seems that this author (and many others) are saying that these methods shouldn't be tested at all!

I think that any sufficiently complex implementation warrants tests of one kind or another. Perhaps I can simply write a static method, check(), which runs a bunch of "unit tests" on the private methods of a class. Calling this method will create instances of the class as necessary and test behavior of the implementation details that warrant testing. The method will return true if the tests all pass, and the method will be meaningless to anyone who wants to just use the class rather than verify that it passes its own correctness checks.

Of course, this method could be removed or conditionally-compiled out in production code to clean up the interface. If it is removed though, the information about the correctness tests on the class disappears and this seems like a poor option. I wonder why no one has devised a test framework which allows the testing of private methods, even if the philosophy seems to be that it would be a bad idea. If it's such a bad idea, shouldn't developers be allowed to shoot themselves in the foot if they so desire? I hardly see how this would be the case, but it seems there is enough of an argument for unit testing private functions that the functionality shouldn't be so easily overlooked.

Here's an article which summarizes the pro's and con's of private testing:

I think my final opinion on the matter is going to be the one which seems most in line with the unit testing philosophy, and is the opinion that I started off with: "Anything that can break, should be tested." Furthermore, those tests should be as direct as possible and not have to go through the middle layer of a public interface, if the code in question is in fact a private method.

No comments:

Post a Comment