Sinara_Pos_DIGITAL

Unit Testing Private Methods Within a Class

This article is part of a series on software testing that will be expanded and updated over time. Software testing is a wide and varied subject, so we will aim to draw attention to certain topics of interest in a number of areas. This entry considers the unit testing of private methods within a class. Many (more…)

Introduction

This article is part of a series on software testing that will be expanded and updated over time. Software testing is a wide and varied subject, so we will aim to draw attention to certain topics of interest in a number of areas. This entry considers the unit testing of private methods within a class. Many would say that the idea is fundamentally flawed and that only public methods need to be unit tested, given that well designed unit tests will implicitly exercise all private methods. Whilst that is true in general, should it always apply?

Unit testing

First, a recap of unit testing. This is an important aspect of software development, helping ensure that discrete parts of code (classes, functions, modules, etc.) work correctly as independent units. It is no substitute for full system testing, but provides a degree of reassurance that changes to the code have not introduced problems and that each part of the program operates as intended. When the units are combined into the final program, the focus can move to resolving integration issues.

In object-oriented programming, the units to be tested are typically the classes. Each class will have a set of tests that create instances of the class and call the various methods using test data, ensuring that the result is as expected.

Testing private methods

Normally, it will be the public methods of the class that are called from the unit tests. There is considerable debate on the merits of also unit testing the private methods of a class as opposed to testing only the public interface. A strong argument is that private methods should be tested indirectly when the public methods that call them are tested.

Another point is that a unit test would be broken if, for example, the private methods being tested were refactored; this also violates the principle that unit tests should test the behaviour of classes rather than their implementation.

A related argument is that if a class has complex private methods that need unit testing, then perhaps that functionality should be factored out into a separate class.

However, factoring out an algorithm (say) into a separate class may result in an inelegant design, with tightly coupled classes, and with a complex mutual interface, resulting in code that is more difficult to maintain and test. In this case it may be reasonable to test private methods directly.

Example code

In .NET, it is possible to do this using Visual Studio’s unit testing framework. This is illustrated by the following example C# program:

using Microsoft.VisualStudio.TestTools.UnitTesting;
 
class MyClass
{
 private int MyPrivateMethod(int val)
 {
  return val * 2;
 }
}
  
static class Program
{
 static void Main()
 {
  MyClass obj = new MyClass();
  PrivateObject testPrivate = new PrivateObject(obj);
  int ret = (int)testPrivate.Invoke("MyPrivateMethod", 100);
  Console.WriteLine(ret);
 }
}

This is possible due to the reflection capabilities in .NET. As an experiment, it is possible to replicate PrivateObject’s functionality using generics and extension methods for a cleaner interface:

static class TestExtensions
{
 static T InvokePrivateMethod(this object objToTest, string methodToTest, params object[] methodParams)
 {
  Type type = objToTest.GetType();
  MethodInfo method = type.GetMethod(methodToTest, BindingFlags.NonPublic | BindingFlags.Instance);
  return (T)method.Invoke(objToTest, methodParams);
 }
}
 
static class Program
{
 static void Main()
 {
  MyClass obj = new MyClass();
  int ret = obj.InvokePrivateMethod("MyPrivateMethod", 100);
  Console.WriteLine(ret);
 }
}

You can read more about extension methods on MSDN.

Opinions on the value of unit testing private methods may vary but sometimes you may have good reason to do it. In these cases your development framework should help, and in some cases can be improved upon as in the above examples.

Share the Post:

Related Posts