C# Access Modifiers and Unit Tests

2011-01-23

Access modifiers (public, private, protected, internal) for C++, Java, and C# were designed before unit testing really became popular, and it’s hard to write unit tests against non-public methods. I like the pattern of putting all tests into a separate package/assembly, so you can easily separate them from a production build. You can also use naming conventions, but that seems less robust. When I’ve tried that approach, inevitably some support classes for tests, like mock objects, leaked into the production release. That can be dangerous. But if you put your tests into a separate assembly, how do you test non-public methods?

Some people say you shouldn’t test non-public methods, but that sounds to me like coder religion. Why not? I find it very useful, when separating a big method into helper methods, to test the helper methods individually so I know they’re right. If the code is complex enough to warrant a helper method, it may be complex enough to warrant a test. I’ve been writing a lot of financial computation code lately, and that’s the kind of thing you need to get right. I’ve never been so diligent about writing unit tests as now. It’s quite handy to test units smaller than public method calls. So how do you do it?

One solution is to mark everything as public. I confess this actually appeals a little to my practical side. As long as you’re not building a truly public API (and few business programmers are), it’s okay to leave helper methods as public. It’s easy to spend unnecessary time thinking about public vs. private, and inevitably you wind up too strict somewhere so you waste time going back and changing things.

But ultimately I prefer to keep helper methods private. It is self-documenting. When you read someone else’s code (including month-ago you), it’s a relief to know that some methods are never called from outside the class. It helps you understand a method’s intent if public and private mean something. Isolating the true public methods can substantially lighten the complexity burden of understanding how a class works. Also, a private method doesn’t need its inputs sanitized quite so rigorously. And with Visual Studio, keeping helper methods private improves IntelliSense, if you use that. So I want to take advantage of private and friends, if I can make it work with unit testing.

Fortunately, C# offers a way to do this. In Properties/AssemblyInfo.cs, you can add a line like this:

[assembly:InternalsVisibleTo("FooTests")]

Then, whatever methods you mark internal are accessible to your test project. (Remember that internal allows access from anywhere in the same assembly.) Sadly this attribute doesn’t open up private methods, but if your development group knows that internal is basically synonymous with private, it’s not a bad compromise. It still lets you distinguish between the public API and everything else. I like this approach a lot.

blog comments powered by Disqus Prev: Visual Studio Unit Tests with Resources Next: No luck trying out Scala