Introduction

Test Driven Development is the
practice of (1) writing tests, (2) writing code that passes those tests, and (3)
then refactoring. This concept is becoming very popular in the .NET community
due to the quality assurance that it adds. While it is easy to test public
methods, the natural question emerges "How do I test protected and private
methods?"

This article will:

Summarize some key points of the "Should-you-even-test private methods
debate"?

Make the case that it is still useful to at least know how to test private
and protected methods - regardless of which side of the debate you're on.

Provide the theory and downloadable code sample to demonstrate these testing
techniques.

Background Theory

Should You Test Private Methods?

A Google
search will show you that there's a lot of debate about using private
methods, let alone testing them. The table below summarizes some of the common
views of the pro and con for both issues.

Pro

Con

Use private methods

Encapsulation - Private methods provide encapsulation, which makes
the code easier for the end client to use

Refactoring - It is easier to refactor private methods because they
are never directly called by external clients, therefore changing the signature
won't break any method calls.

Validation - Unlike public methods that must validate all input
because they are called by external clients, private methods are called safely
within the class and don't require the same rigor of validation - the inputs
should have been already validated in the public methods.

Test Scope - Exposing every method as public greatly increases the
test scope. Private methods are used only how the developer intended them,
whereas public methods need to be tested for every possible case which required
a broader test scope.

Didn't Refactor - If a class is complicated enough to merit private
members, then it should be refactored.

Test Control - Private methods can contain complex logic and it
increases test control to be able to directly access the method and test it,
instead of needing to indirectly accessing it through a public method.

Principle - Unit Testing is about testing the smallest functional
piece of code; private methods are functional pieces of code, therefore on
principle private methods should be testable.

Already Covered - Only the public interface should be tested. Private
methods should already have thorough test coverage from being called by the
public methods that are tested.

Brittle Code - If you refactor the code, and juggle around the
private methods, and if you had tests linked to those private methods, then you
need to juggle around your tests too.

There are bright and experienced people on both sides of the issue. So while
I have no intention or expectation of ending the "should I test private method"
debate, there is still value for both sides to know how to test them. Even if
you think that private methods should not be tested:

Your opinion will be more influential if you can at least show that you are
able to test them, but choose not to (i.e. you're not saying "Don't test private
methods" simply because you don't know how).

Having the option of testing non-public methods lets you see what really
works best for your team over time.

As long as there are still some valid situations, it's worth having a
convenient way to test them.

Good Criteria and Inadequate Techniques

There are three additional criteria that any testing overhead for
private/protected methods should meet:

Transparency - Don't alter the System Under Test (SUT), such as
adding wrapper methods in the production code.

Scope - Be able to run in both Debug and Release mode.

Simplicity - Have minimal overhead, and hence be easy to change and
simple enough to introduce minimal risk.

Keeping these criteria in mind, there are several strategies that fall
short:

Strategy

Problem

Don't have any private methods.

This avoids the issue.

Use the directives #if DEBUG ... #endif
to wrap a public method which in turns wraps the private method. The unit tests
can now indirectly access that private method through the public wrapper. (This
is a method that I myself have used many times, and found it to be tedious and
non-object oriented).

This only works in Debug mode.

This is procedural and not object-oriented. We would need to wrap the
individual methods in both the production code and unit tests.

This alters the SUT by adding the public method
wrappers.

Use the [Conditional("DEBUG")] attribute
on public methods that wrap the private methods.

This only works in Debug mode.

Create internal methods to access the private method;
then have a public test class elsewhere in the assembly that wraps those
internal methods with public ones.

This alters the release code by adding the internal hooks, ultimately making
the private methods accessible in production.

This requires a lot of extra coding, and is hence
brittle.

Testing Protected Methods

A protected method is visible only to derived classes, therefore it is not
immediately available to a test suite. For example, suppose we wanted to test
the method from ClassLibrary1.MyObject:

The book Pragmatic
Unit Testing in C# with NUnit explains one solution: make a derived class
MyObjectTester that inherits class MyObject, and then
create a public method TestMyProtectedMethod that wraps the
protected one. For example:

By using inheritance and putting the
MyObjectTester class in the UnitTests assembly, it
doesn't add any new code to the production assembly.

Scope

Nothing in this approach depends on Debug-only
techniques.

Simplicity

Although this approach requires a new derived class,
and an additional public wrapper method for each protected method, it is
object-oriented and type safe.

Testing Private Methods

Testing private methods is a little more involved; but we can still do it
using System.Reflection.
You can use Reflection to dynamically access methods of a type, including both
instance and static private methods. Note that accessing private methods does
require the ReflectionPermission,
but that is not a problem for Unit Tests running on a development machine or
build server.

Suppose we wanted to test the private method MyPrivateMethod
from ClassLibrary1.MyObject:

One solution is to create a UnitTestUtilities project with a helper class to
call the test method via reflection. For example, the download solution has the
following methods in UnitTestUtilities.Helper:

Private method RunMethod takes in the necessary parameters that
Reflection needs to invoke a method, and then returns the value. It has two
public methods that wrap this: RunStaticMethod and
RunInstanceMethod for static and instance methods respectively.

Walking through RunMethod, it first gets the

MethodInfo

from a type. Because we expect this to only be called for existing
methods, a null method triggers an Exception. Once we have the
MethodInfo, we can invoke the method given the instantiated object
(null for static methods) and the parameter array.

The only extra code we created -
UnitTestUtilities, is not shipped in production.

Scope

Nothing in this approach depends on Debug-only
techniques.

Simplicity

This approach can call any method with a single call.
Once you have the UnitTestUtilities, the only complication is
creating the correct parameters (method name, data types, etc...) for
RunInstanceMethod or RunStaticMethod. Because the
method is being dynamically called, the parameters aren't checked at compile
time.

Conclusion

While there is a debate on whether or not to test private methods, at least
we have the ability to do so. We can test protected methods using inheritance to
create a derived TesterClass that wraps the base protected methods
with public ones. We can test private methods using Reflection, which can be
abstracted to a UnitTestUtility helper class. Both of these
techniques can help to improve test coverage.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

Share

About the Author

Tim Stall is a Chicago-based technical consultant for Computer Sciences Corporation (www.csc.com), a leading global IT services company. In addition to his expertise in Microsoft.Net development projects and enterprise architecture, Tim's .Net experience includes, writing technical publications, leading internal training, and having MCAD certification. His blog is at http://timstall.dotnetdevelopersjournal.com/.

Then in my unit tests I can call the TEST_... method and for other code I know that any method beginning TEST_... won't be available in the release build, so I just don't use it. Visual Studio is also quite good at helping as it will grey out the text in the DEBUG block if I've got the current build set to DEBUG.

It is also possible to create your own blocks and have a special unit test build.

Also, I ensure that the test method is named exactly the same as the original method but with a "TEST_" prefix on it. Ever since I started taking the Cradle-to-grave naming concept seriously I cannot believe how much time I've saved by not having to think about what such and such a method or variable is called.

You mention in the article: "This only works in Debug mode." Is that really such a big deal? If it is, then there is nothing to stop you defining a UNITTEST block and having a release build with the additional tests in it.

You also wrote: "This is procedural and not object-oriented. We would need to wrap the individual methods in both the production code and unit tests." I don't see why you are wrapping the methods in the production code. The compiler will strip out the wrappers in production code as they won't be used in the production code. I also don't see how it "is procedural"

And: "This alters the SUT by adding the public method wrappers." I don't see this as a problem. No more of a problem that inheriting and putting the wrapper in the derived class, or creating a wrapper using reflection.

Hey Colin,
Thanks for the feedback. Keep in mind that I initially started using #if DEBUG … #endif. It does work, and is certainly better than no test at all.

> You mention in the article: "This only works in Debug mode." Is that really such a big deal?
Why not take the approach that lets you run tests on the Release build - the same code shipped to the client? In your sample, you’ve done all the work to create a test for MyPrivateMethod, and while you can run it in debug mode guaranteeing some degree of success (if it passes in Debug, it will probably pass in Release), you can’t run it in Release.

> I don't see why you are wrapping the methods in the production code.
> And: "This alters the SUT by adding the public method wrappers."
The gist of my point is that you need to physically alter the source code file by (1) wrapping creating public TEST_xxx methods, and (2) wrapping these methods in #if DEBUG … #endif (or something similar like “UNITTEST). These alterations do not add any feature to the client; they are used only to assist in testing.

> I also don't see how it "is procedural"
It encloses #if DEBUG … #endif directives around each method/group of methods instead of applying them at the object level. Perhaps it would be clearer to think of it as “not object oriented”.

TimStall wrote:if it passes in Debug, it will probably pass in Release

Ah... Okay - I take your point, they may be some subtle difference between debug and release that isn't obvious or immediately apparent.

I orignally wrote:I don't see why you are wrapping the methods in the production code

TimStall responded:The gist of my point is that you need to physically alter the source code file by (1) wrapping creating public TEST_xxx methods, and (2) wrapping these methods in #if DEBUG … #endif (or something similar like "UNITTEST"). These alterations do not add any feature to the client; they are used only to assist in testing.

I guess point 1 will be mitigated in C# 2.0 and the introduction of partial classes - no longer need to modify the original source file as these wrappers can be added in a secondary source file.

As for point 2: I see that they don't add anything to the client, but why is the client caring about unit tests?

TimStall wrote:Perhaps it would be clearer to think of it as “not object oriented”.

I think this is a point that will sink in over the course of the next few days, but for the moment I cannot see a problem creating a #if UNITTEST block next to a method to expose it publicly in a unit testing build (i.e. Effectively a debug or release type build with unit testing wrappers in it). The wrapper is simply has an identical signature (save for the public exposure and the "TEST_" prefix) and does nothing but call the private method.

Anyway - It might make more sense when I get a chance to play with these ideas over the weekend.

> I cannot see a problem creating a #if UNITTEST block next to a method to expose it publicly

While I agree that it works, one reason that I switched is because it requires writing a bunch of extra test code. The approach I outlined requires only a single utility method once - not a new wrapper for each private method.

Hey Mark,
Glad you enjoyed the article. That’s an interesting idea of having the test class directly inherit the System-Under-Test (SUT) class.
Question: If you have a base test class for common testing functionality, and a class can only inherit directly from one other class, does this approach run into problems? I.e. your test class can’t inherit from both a Test-Base class and (SUT) class.

I have used the "TextFixture inherits tested class" mechanism as well. The only concern is that since the fixture is instantiated only once, you're maintaining state in between individual test methods. In the "Expose protected methods via public methods in a separate tester class" mechanism, you'd probably have the instantiation of the SUT in the [SetUp] and therefore a new SUT instance would be used for each test.