joydip_kanjilal
Contributor

How to unit test static methods in C#

how-to
Aug 24, 20208 mins
C#Microsoft .NETSoftware Development

Learn when static methods can’t be unit tested and how to use wrapper classes and the Moq and xUnit frameworks to unit test them when they can

Movie preview test pattern
Credit: Thinkstock

When building or working in .NET applications you might often use static methods. Methods in C# can be either static or non-static. A non-static method (also known as an instance method) can be invoked on an instance of the class to which it belongs. Static methods don’t need an instance of the class to be invoked — they can be called on the class itself.

Although testing a non-static method (at least one that doesn’t call a static method or interact with external dependencies) is straightforward, testing a static method is not an easy task at all. This article talks about how you can overcome this challenge and test static methods in C#. 

[ Also on InfoWorld: How to refactor God objects in C# ]

To work with the code examples provided in this article, you should have Visual Studio 2019 installed in your system. If you don’t already have a copy, you can download Visual Studio 2019 here.  

Create a .NET Core console application project in Visual Studio

First off, let’s create a .NET Core Console Application project in Visual Studio. Assuming Visual Studio 2019 is installed in your system, follow the steps outlined below to create a new .NET Core console application project in Visual Studio.

  1. Launch the Visual Studio IDE.
  2. Click on “Create new project.”
  3. In the “Create new project” window, select “Console App (.NET Core)” from the list of templates displayed.
  4. Click Next.
  5. In the “Configure your new project” window shown next, specify the name and location for the new project.
  6. Click Create. 

This will create a new .NET Core console application project in Visual Studio 2019. In similar fashion, create two more projects – a class library and a unit test (xUnit test) project. We’ll use these three projects to illustrate unit testing of static methods in the subsequent sections of this article.

When a static method can and can’t be unit tested

Unit testing a static method is no different than unit testing a non-static method. Static methods are not untestable in themselves. A static method that holds no state or doesn’t change state can be unit tested. As long as the method and its dependencies are idempotent, the method can be unit tested. The problems arise when the static method calls other methods or when the object being tested calls the static method. On the other hand, if the object being tested calls an instance method, then you can unit test it easily.

A static method cannot be unit tested if any of the following holds true: 

  • The static method interacts with external dependencies such as a database, file system, network, or external API.
  • The static method holds state information, i.e., if it caches data into a static object of the class.

Consider the following code snippet that shows two classes, namely ProductBL and Logger. While ProductBL is a non-static class, Logger is a static class. Note that the Write method of the Logger class has been called from the LogMessage method of the ProductBL class.

public class ProductBL
    {
        public void LogMessage(string message)
        {
            Logger.Write(message);
        }
    }
    public class Logger
    {
        public static void Write(string message)
        {
           //Write your code here to log data
        }
    }

Assume that the Write method of the Logger class connects to a database and then writes the data to a database table. The name of the database and its table where the data should be written might be pre-configured in the appsettings.json file. How can you now write unit tests for the ProductBL method?

Note that static methods cannot be mocked easily. As an example, if you have two classes named A and B and class A uses a static member of class B, you wouldn’t be able to unit test class A in isolation.

Three ways to unit test static methods

You can use Moq to mock non-static methods but it cannot be used to mock static methods. Although static methods cannot be mocked easily, there are a few ways to mock static methods.

You can take advantage of the Moles or Fakes framework from Microsoft to mock static method calls. (The Fakes framework was included in Visual Studio 2012 as the successor to Moles – it is the next generation of Moles and Stubs.) Another way to mock static method calls is by using delegates. There is yet another way to mock static method calls in an application – by using wrapper classes and dependency injection.

IMHO this last option is the best solution to the problem. All you need to do is wrap the static method call inside an instance method and then use dependency injection to inject an instance of the wrapper class to the class under test.

Create a wrapper class in C#

The following code snippet illustrates the LogWrapper class that implements the IWrapper interface and wraps a call to the Logger.Write() method inside an instance method called LogData.

public class LogWrapper : IWrapper
    {
        string _message = null;
        public LogWrapper(string message)
        {
            _message = message;
        }
        public void LogData(string message)
        {
            _message = message;
            Logger.Write(_message);
        }
    }

The following code snippet shows the IWrapper interface. It contains the declaration of the LogData method.

public interface IWrapper
    {
        void LogData(string message);
    }

The ProductBL class uses dependency injection (constructor injection) to inject an instance of the LogWrapper class as shown in the code listing given below.

public class ProductBL
    {
        readonly IWrapper _wrapper;
        static string _message = null;
        public ProductBL(IWrapper wrapper)
        {
            _wrapper = wrapper;
        }
        public void LogMessage(string message)
        {
            _message = message;
            _wrapper.LogData(_message);
        }
    }

The LogMessage method of the ProductBL class calls the LogData method on the instance of the LogWrapper class that has been injected earlier.

Use xUnit and Moq to create a unit test method in C#

Open the file UnitTest1.cs and rename the UnitTest1 class to UnitTestForStaticMethodsDemo. The UnitTest1.cs files would automatically be renamed to UnitTestForStaticMethodsDemo.cs. We’ll now take advantage of the Moq framework to set up, test, and verify mocks.

The following code snippet illustrates how you can use the Moq framework to unit test methods in C#.

var mock = new Mock<IWrapper>();
mock.Setup(x => x.LogData(It.IsAny<string>()));
new ProductBL(mock.Object).LogMessage("Hello World!");
mock.VerifyAll();

When you execute the test, here’s how the output should look in the Test Explorer Window.

moq static method unit test IDG

Figure 1. Moq unit test output. 

The complete code listing of the test class is given below for your reference.

public class UnitTestForStaticMethodsDemo
    {
        [Fact]
        public void StaticMethodTest()
        {
            var mock = new Mock<IWrapper>();
            mock.Setup(x => x.LogData(It.IsAny<string>()));
            new ProductBL(mock.Object).LogMessage("Hello World!");
            mock.VerifyAll();
        }
    }

Unit testing is a process that tests units of code in an application to check if the actual results from your unit test match the desired results. If used judiciously unit testing can help prevent bugs in the development phase of a project.

Static methods can pose a number of problems when you attempt to unit test them using mocks. If your application requires you to mock a static method, you should consider that a design smell – i.e., an indicator of a bad design. I’ll discuss mocks, fakes, and stubs in more detail in a future article here.

How to do more in C#:

joydip_kanjilal
Contributor

Joydip Kanjilal is a Microsoft Most Valuable Professional (MVP) in ASP.NET, as well as a speaker and the author of several books and articles. He received the prestigious MVP award for 2007, 2008, 2009, 2010, 2011, and 2012.

He has more than 20 years of experience in IT, with more than 16 years in Microsoft .Net and related technologies. He has been selected as MSDN Featured Developer of the Fortnight (MSDN) and as Community Credit Winner several times.

He is the author of eight books and more than 500 articles. Many of his articles have been featured at Microsoft’s Official Site on ASP.Net.

He was a speaker at the Spark IT 2010 event and at the Dr. Dobb’s Conference 2014 in Bangalore. He has also worked as a judge for the Jolt Awards at Dr. Dobb's Journal. He is a regular speaker at the SSWUG Virtual Conference, which is held twice each year.

More from this author