Mocking a static method

Mocking a static method

Recently, I found myself unit testing some legacy code which involves mocking a static class that make some calls to the database. As you can imagine, it's a little bit tricky to mock a static class as there is no direct way of overriding its methods. Searching the internet, it is suggested that static methods have to be wrapped in a class that implements in an interface that calls the method.

So imagine I have a service like below:

public class SomeDataService
{
    public string? GetNameById(int Id)
    {
        return SomeDataRepository.GetSomeDataById(Id)?.Name;
    }
}        

The class SomeDataRepository is a static class with a static method like this:

public static class SomeDataRepository
{
    public static SomeData? GetSomeDataById(int id)
    {
        IList<SomeData> data = new List<SomeData>
        {
            new SomeData { Id = 1, Name = "John" },
            new SomeData { Id = 2, Name = "Jane" }
        };

        return data.FirstOrDefault(x => x.Id == id);
    }
}        

My task is to unit test GetNameById method and therefore requires me to mock SomeDataRepository.

Following the suggestion, I have done the following::

1. Created an interface ISomeDataRepository to abstract the repository.

public interface ISomeDataRepository
{
    SomeData? GetSomeDataById(int id);
}        

2. Implemented the interface which calls the static class' method

    public class SomeDataRepositoryWrapper : ISomeDataRepository
    {
        public SomeData? GetSomeDataById(int id)
        {
            return SomeDataRepository.GetSomeDataById(id);
        }
    }        

3. Modified SomeDataService to depend on ISomeDataRepository via dependency injection.

    public class SomeDataService
    {
        private readonly ISomeDataRepository _repository;

        public SomeDataService(ISomeDataRepository repository)
        {
            _repository = repository;
        }

        public string? GetNameById(int id)
        {
            return _repository.GetSomeDataById(id)?.Name;
        }
    }        

4. This allows me to create unit tests for SomeDataService. Note: the following unit test uses xUnit and nSubstitute

public class SomeDataServiceTests
{
    [Fact]
    public void GetNameById_ShouldReturnName_WhenIdExists()
    {
        // Arrange
        var repository = Substitute.For<ISomeDataRepository>();
        repository.GetSomeDataById(1).Returns(new SomeData { Id = 1, Name = "John" });

        var service = new SomeDataService(repository);

        // Act
        var result = service.GetNameById(1);

        // Assert
        Assert.Equal("John", result);
    }

    [Fact]
    public void GetNameById_ShouldReturnNull_WhenIdDoesNotExist()
    {
        // Arrange
        var repository = Substitute.For<ISomeDataRepository>();
        repository.GetSomeDataById(Arg.Any<int>()).Returns((SomeData)null);

        var service = new SomeDataService(repository);

        // Act
        var result = service.GetNameById(99);

        // Assert
        Assert.Null(result);
    }
}        

Then of course, I registered the interface in the DI container.


What do you think? Is there a better way of mocking a static class?





To view or add a comment, sign in

Explore content categories