In this article, we’ll take a closer look at how we can mock IConfiguration.GetValue when writing unit tests in ASP.NET Core.

To download the source code for this article, you can visit our GitHub repository.

Let’s start!

Mock IConfiguration.GetValue in ASP.NET Core

Before we start mocking, we need a class that utilizes IConfiguration:

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!
public class FinanceService(IConfiguration configuration) : IFinanceService
{
    public double CalculateTotalAmount(double hours)
    {
        var hourlyRate = configuration.GetValue<double>("FinanceSettings:HourlyRate");

        return hourlyRate * hours;
    }
}

We create the FinanceService class and inject an IConfiguration instance using a primary constructor. Next, we create the CalculateTotalAmount() method that takes a double as a parameter, representing the hours worked. Then, inside the method, we use the GetValue() method from IConfiguration to get the hourly rate from our configuration file. Finally, we return the total amount.

Do you want to know more about the different configuration providers in ASP.NET Core? Then you can check out our article ASP.NET Core Configuration – Configuration Providers.

Next, we’ll explore how we can mock the GetValue() method using two of the most popular mocking libraries – Moq and NSubstitute.

How to Mock IConfiguration.GetValue Using Moq

After we’ve created our test project, we create a new test class. After this is done, we can start writing our test:

[Theory]
[InlineData(1)]
[InlineData(1.5)]
[InlineData(1000)]
public void WhenCalculateTotalAmountIsInvoked_ThenValidResultIsReturned(double hours)
{
    // Arrange
    const string rate = "25.50";
    var mockedSection = new Mock<IConfigurationSection>();
    mockedSection.Setup(x => x.Value)
        .Returns(rate);

    var configuration = new Mock<IConfiguration>();
    configuration.Setup(x => x.GetSection("FinanceSettings:HourlyRate"))
        .Returns(mockedSection.Object);

    var financeService = new FinanceService(configuration.Object);

    // Act
    var result = financeService.CalculateTotalAmount(hours);

    // Assert
    result.Should().Be(hours * double.Parse(rate));
}

We start by mocking an IConfigurationSection instance. Then we use the Moq‘s Setup() method to select the Value property of the configuration section and then use the Returns() method to return a string representation of our hourly rate. This is a vital step that should not be missed as the GetValue() method ultimately calls the GetSection() method behind the scenes.

Next, we continue with mocking IConfiguration itself. Also, we use the Setup() and Returns() methods, to specify that when we call the GetSection() method with FinanceSettings:HourlyRate as a parameter, it will return the already mocked IConfigurationSection instance.

After this is done, we create a new instance of our FinanceService class by passing the Object property of the mocked IConfiguration instance and call the CalculateTotalAmount() method to get the result. Finally,  we assert that it should be equal to the multiplication result of our hourly rate and the hours worked.

How to Mock IConfiguration.GetValue Using NSubstitute

Let’s create a new class and test method so we can utilize NSubstitute:

[Theory]
[InlineData(1)]
[InlineData(1.5)]
[InlineData(1000)]
public void WhenCalculateTotalAmountIsInvoked_ThenValidResultIsReturned(double hours)
{
    // Arrange
    const string rate = "25.50";
    var mockedSection = Substitute.For<IConfigurationSection>();
    mockedSection.Value.Returns(rate);

    var configuration = Substitute.For<IConfiguration>();
    configuration.GetSection("FinanceSettings:HourlyRate")
        .Returns(mockedSection);

    var financeService = new FinanceService(configuration);

    // Act
    var result = financeService.CalculateTotalAmount(hours);

    // Assert
    result.Should().Be(hours * double.Parse(rate));
}

As we already know it’s mandatory to mock IConfigurationSection, we use NSubstitute‘s For<T>() method to create one. Here, we don’t have a setup method, so we access the Value property directly and follow it with the Returns() method to which we pass our rate as a string.

Next, we create a mock for IConfiguration and using the Returns() method again, specifying that when we call the GetSection() method with FinanceSettings:HourlyRate as a parameter, we will get our mocked configuration section.

If you want to know more about NSubstitute, check out our article Effective Mocking With NSubstitute in .NET.

Then, in the rest of our test, we instantiate FinanceService class, call it’s CalculateTotalAmount() method and assert that it returns the expected result.

How to Create IConfiguration Instead of Mocking It in ASP.NET Core

Mocking IConfiguration with either Moq or NSubstitute does require a bit of effort as we need to mock IConfigurationSection as well. There is a way we can create a configuration instance without relying on external libraries.

Let’s examine this approach:

[Theory]
[InlineData(1)]
[InlineData(1.5)]
[InlineData(1000)]
public void WhenCalculateTotalAmountIsInvoked_ThenValidResultIsReturned(double hours)
{
    // Arrange
    const string rate = "25.50";
    var configuration = new ConfigurationBuilder()
        .AddInMemoryCollection(new Dictionary<string, string?>
        {
            {"FinanceSettings:HourlyRate", rate}
        })
        .Build();

    var financeService = new FinanceService(configuration);

    // Act
    var result = financeService.CalculateTotalAmount(hours);

    // Assert
    result.Should().Be(hours * double.Parse(rate));
}

In a test method, we start by creating a new instance of the ConfigurationBuilder class. Then we use the AddInMemoryCollection() method that will add an in-memory collection to the configuration provider. The method requires an IEnumerable<KeyValuePair<string, string?>> instance as a parameter, to satisfy this condition we pass a Dictionary<string, string?> that has the FinanceSettings:HourlyRate as a key and the hourly rate as a value.

The Options Pattern is a better alternative to using IConfiguration, you can check our article if you are not familiar with it ASP.NET Core Configuration – Options Pattern.

Finally, we call the Build() method to instantiate an IConfigurationRoot instance. It implements the IConfiguration interface so we can safely use it to create an instance of our FinanceService class and test its CalculateTotalAmount() method.

Conclusion

In this article, we saw that mocking the IConfiguration.GetValue method is a vital skill when writing unit tests. We can leverage libraries like Moq and NSubstitute, to simulate the configuration environment, ensuring our tests are isolated and reliable. But we must be sure also to mock the configuration section as it is a dependency of the GetValue method. Alternatively, we explored how to build an in-memory configuration provider without relying on external providers. By mastering both approaches, we can ensure that our applications are robust and maintainable, with reliable unit tests that accurately simulate real-world configurations.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!