Tuesday, March 30, 2010

a balanced look at unit tests of internal classes

"Internal" C# classes are only accessible to other classes in the same assembly. One of the guidelines for unit testing is to test public interfaces because a unit test should simulate real usage of the class by other classes. So are unit tests of internal C# classes a good idea or not?

Yes, because:
  • Good OO design recommends smaller, cohesive classes of singular purpose. If someone has such a design but creates unit tests just for the public classes, isn't there a good chance in practice that the indirect test coverage will fail to fully check all the possible code paths of the internal classes?
  • The members of internal classes still have separate private and public visibilities within the assembly. If a change to an internal class subtly breaks its "public" contract with other classes within the assembly and this goes undetected due to no unit tests, isn't that likely to cause problems whose ultimate impact could affect code outside the assembly as well?
  • Efforts to write unit tests for the internal classes could motivate a programmer to reconsider the reusability of those classes. He or she might realize that, with a little redesign, the internal classes could be broadly useful public classes that other programmers can exploit. Isn't this a good outcome?
No, because:
  • Internal classes are designated internal for a reason. Test gurus often intone the mantra, "Listen to what the test is telling you." If someone ever needed to make unit tests for an internal class, then should the class really be public, not internal?
  • Hidden OO elements like internal classes offer the freedom to change without breaking other code. But by writing unit tests for internal classes, a programmer forgoes this freedom and thereby accepts the tedium of keeping the unit tests up-to-date with each change. Doesn't this constitute "busy work" that's irrelevant by definition to all code outside the assembly?
  • Efforts to write unit tests could motivate a programmer to change the visibility of one or more "utility" classes to public for the sake of testing. Later, another programmer searches across modules and assemblies in an attempt to complete a common task that should be already be implemented in one place. He or she stumbles on the test-enabled classes and happily starts to use it for his scenario. Unfortunately, the methods of the class have side effects that don't make any sense out of the original context for the exposed class. Customers start complaining about these side effects. Isn't this a bad outcome?
The title only mentioned a balanced look. It didn't claim to reach a conclusion.

No comments:

Post a Comment