How to test a private method of a class?

by

in

Today I got a question from my collegue how to test a method that is marked as private on a class? My first reaction was ‘well just make it public’ but of course that would break the class encapsulation, and there are ways to actually test a private method without breaking this encapsulation.

What you have to do in your test class is to create a small TestWrapper of the class under test. This SUT (Subject Under Test) will than inherit all methods of the parent class, and can access those methods. When this TestWrapper than has a public available copy of the private method that it is inheriting, you can easily access this private method from your unit test.

Here’s the example of the testclass and the SUT:


using System;
using System.CodeDom;
using NUnit.Framework;

namespace Core.UnitTest
{
   [TestFixture]
   public class UnitTest1
   {

     [Test]
     public void CallPrivateMethod_On_TestWrapper_ReturnsResult()
     {
        var SubjectUndertest = new TestWrapperClassToTest();
        int result = SubjectUndertest.CallsInternalMethod(2, 2);
        Assert.That(result == 4);
     }


     public class TestWrapperClassToTest : ProductionCodeClass
     {
        public int CallsInternalMethod(int a, int b)
        {
           return this.CallsInternalMethod(a, b);
        }
     }
 }
 // end unit test class

 
 public class ProductionCodeClass
 {
    public void CodeEntryPointMethod()
    {
       int i = CallsInternalMethod(1,1);
    }

    private int CallsInternalMethod(int a, int b)
    {
        return a+b;
    }
  }
}

Ok that was funny, of course. Because if you try this at home you will get:

stackoverflowexception

 

The problem here is that the CallsInternalMethod is not calling the base-private method at all. It is a recursive loop, calling itself untill the Stack memory is full.

So we found we can’t test a private method! How can we bend the rules a bit without making the private method publicly available? Wel in C# there is the possibility to make a method ‘protected’ which does make the method available for inheriting classes. Like so:

using System;
using System.CodeDom;
using NUnit.Framework;

namespace TestSandBox.UnitTest
{
    [TestFixture]
    public class TestSomeClass
    {

        [Test]
        public void CallProtectedMethod_On_TestWrapper_ReturnsResult()
        {
            var SubjectUndertest = new TestWrapperClassToTest();
            int result = SubjectUndertest.CallsInternalMethodAccessor(2, 2);
            Assert.That(result == 4);
        }


        public class TestWrapperClassToTest : ProductionCodeClass
        {
            public int CallsInternalMethodAccessor(int a, int b)
            {
                return this.CallsInternalMethod(a, b);
            }
        }
    }
    // end unit test class


    public class ProductionCodeClass
    {
        public void CodeEntryPointMethod()
        {
            int i = CallsInternalMethod(1, 1);
        }

        protected int CallsInternalMethod(int a, int b)
        {
            return a + b;
        }
    }
}

As you can see the protected keyword is the way to keep methods private enough to not expose the method for instances of the class, while it does enable access of the method to inheriting classes. This way, the productioncodeClass still only has the CodeEntryPointMethod() publicly available while we can still test the CallsInternalMethod via an inherited class that we create as a stub to enable accessing the protected method. And testing this method directly in the unit test is what we tried to achieve!

You can find the above code on github:

https://github.com/MelleKoning/testsandbox