Unit testing a protected method

How to unit test a protected method on a class

Home DailyDrop

Daily Knowledge Drop

To unit test a protected method of a class, inheritance and a public method wrapper can be used.

Consider a class, (called, for example, CustomClass) with a protected member - a test class (TestCustomClass) can be created which inherits from CustomClass Then a public wrapper method created on TestCustomClass can be created, which in turn invokes the protected method on CustomClass.

This pattern enables the protected member to be accessed and tested through the public test wrapper method.


Protected keyword

A quick recap of the protected keyword - a protected member is accessible within its class and by derived class instances.

For testing, the ""derived class instance"" is the relevent and important piece of information.


Problem

We have a library which performs some business logic, some of it publicly exposed, and some of it protected:

namespace CustomLibrary;

public class CustomClass
{
    public int PerformPublicLibraryLogic()
    {
        // do some processing
        return 0;
    }

    protected int PerformProtectedLibraryLogic()
    {
        // do processing
        return 0;
    }

}

We want to unit test these two methods, so a separate test project is created (a MSTest test project in this example):

namespace CustomApplication.UnitTest;

[TestClass]
public class CustomLibraryUnitTests
{
    [TestMethod]
    // Tests the public method
    public void TestPublic()
    {
        // create an instance and call the public method
        var customclass = new CustomClass();
        var result = customclass.PerformPublicLibraryLogic();

        // check the results
        Assert.AreEqual(0, result);
    }

    [TestMethod]
    // Try test the protected method
    public void TestProtectedBroken()
    {
        var customclass = new CustomClass();
        // THIS WILL NOT COMPILE
        // PerformProtectedLibraryLogic is not accessible
        var result = customclass.PerformProtectedLibraryLogic();
        
        Assert.AreEqual(0, result);
    }
}

The above code will NOT compile, as the PerformProtectedLibraryLogic is not accessible from the test project.


Solution

As mentioned above, the important piece of information related to the protected keyword, is that a protected member is accessible from a derived class instance - so let's create a derived class.

In the test project:

namespace CustomApplication.UnitTest;

// inherit from the class in question
public class TestCustomClass : CustomClass
{
    // create a public method, which wraps the protected method
    public int WrappedPerformProtectedLibraryLogic()
    {
        // as this code is inside a derived class, it has accessibility
        // to the PerformProtectedLibraryLogic method
        return PerformProtectedLibraryLogic();
    }
}

Instead of testing the protected method on the CustomClass directly, it can now be tested through public method on TestCustomClass:

[TestMethod]
// Tests the protected method
public void TestProtectedWorking()
{
    // used the TestCustomClass instead of CustomClass 
    var customclass = new TestCustomClass();
    // invoke the wrapper method
    var result = customclass.WrappedPerformProtectedLibraryLogic();

    Assert.AreEqual(0, result);
}

What's important here is that the TestCustomClass and wrapper method add no additional logic or complexity. We do not want the test class to interfere with the goal of testing the underlying protected method.

Notes

The technique mentioned here is not a ground-breaking revelation, but it is very useful. Personally, I've recently started writing more unit tests in earnest (after not having done any for 5+ years) this was one of the first issues I encountered, I had not experienced before, which needed to be solved.


Daily Drop 117: 15-07-2022

At the start of 2022 I set myself the goal of learning one new coding related piece of knowledge a day.
It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.

The Daily Drop is a record of these pieces of knowledge - writing about and summarizing them helps re-enforce the information for myself, as well as potentially helps others learn something new as well.
c# .net testing unittest protected