Mocking IConfiguration GetValue<T> extension methods in Unit Test

How to mock extension methods for IConfiguration in .NET Core

Now here is a trouble that was bugging me for some time and I guess who ever is using IConfigration injected in the constructor and using extension methods to access configuration values reached whan trying to write Unit Tests.

IConfiguration interface is a great way to easily replace your configuration layer in application, but it has it's drawbacks. The way interface envorces configuration reading is by exposing GetSection method which return IConfigurationSection. This will allow you to read configuration values, but if you need a valu conversion inline, you have to write it yourself. This is not a big deal, but imagine writing it for every place in application? It is a code repeate case.

The obvious way to overcome this problem is simply to use extenson method. No need to write your own, since you can use already build one from Microsoft's NuGet package Microsoft.Extensions.Configuration. Life is beatiful again and you can read your configuration values in the type you want to with the power of extension methods.

The probelm occures when you need to write Unit tests for methods that use this extension method. You simply cannot Mock static methods and extension methods are static methods.

The thing you can mock are methods used by the extension method, so for that purpose I hunt down the actula code of GetValue<T> extension method and found it on Github https://github.com/aspnet/Configuration/blob/master/src/Config.Binder/ConfigurationBinder.cs

namespace Microsoft.Extensions.Configuration
{
/// <summary>
/// Static helper class that allows binding strongly typed objects to configuration values.
/// </summary>
public static class ConfigurationBinder
{
...
/// <summary>
/// Extracts the value with the specified key and converts it to type T.
/// </summary>
/// <typeparam name="T">The type to convert the value to.</typeparam>
/// <param name="configuration">The configuration.</param>
/// <param name="key">The key of the configuration section's value to convert.</param>
/// <returns>The converted value.</returns>
public static T GetValue<T>(this IConfiguration configuration, string key)
{
return GetValue(configuration, key, default(T));
}
/// <summary>
/// Extracts the value with the specified key and converts it to type T.
/// </summary>
/// <typeparam name="T">The type to convert the value to.</typeparam>
/// <param name="configuration">The configuration.</param>
/// <param name="key">The key of the configuration section's value to convert.</param>
/// <param name="defaultValue">The default value to use if no value is found.</param>
/// <returns>The converted value.</returns>
public static T GetValue<T>(this IConfiguration configuration, string key, T defaultValue)
{
return (T)GetValue(configuration, typeof(T), key, defaultValue);
}
/// <summary>
/// Extracts the value with the specified key and converts it to the specified type.
/// </summary>
        /// <param name="configuration">The configuration.</param>
        /// <param name="type">The type to convert the value to.</param>
        /// <param name="key">The key of the configuration section's value to convert.</param>
        /// <returns>The converted value.</returns>
        public static object GetValue(this IConfiguration configuration, Type type, string key)
        {
            return GetValue(configuration, type, key, defaultValue: null);
        }

        /// <summary>
        /// Extracts the value with the specified key and converts it to the specified type.
        /// </summary>
        /// <param name="configuration">The configuration.</param>
        /// <param name="type">The type to convert the value to.</param>
        /// <param name="key">The key of the configuration section's value to convert.</param>
        /// <param name="defaultValue">The default value to use if no value is found.</param>
        /// <returns>The converted value.</returns>
        public static object GetValue(this IConfiguration configuration, Type type, string key, object defaultValue)
        {
            var value = configuration.GetSection(key).Value;
            if (value != null)
            {
                return ConvertValue(type, value);
            }
            return defaultValue;
        }
	...
    }
}
    

You can see from the code snippet from above that GetValue<T> uses GetValue which down the line is calling GetSection. Method GetSection is declared in IConfiguration which means you can mock it, and by mocking it you also mock GetValue<T> as it is wrapping GetSection indirectly through GetValue.

Mock<IConfiguration> configuration = new Mock<IConfiguration>();
this.configuration.Setup(c => c.GetSection(It.IsAny<String>())).Returns(new Mock<IConfigurationSection>().Object);
    

We mocked GetSection in the piece of code above and this will work for GetValue<T>. However we did not directly mocked GetValue<T> which is impossible since it is static, but we did this indirectly by mocking GetSection method.

References

Disclaimer

Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.


About the author

DEJAN STOJANOVIC

Dejan is a passionate Software Architect/Developer. He is highly experienced in .NET programming platform includion ASP.NET MVC and WebApi. He likes working on new technologies and exciting challenging projects

CONNECT WITH DEJAN  Loginlinkedin Logintwitter Logingoogleplus Logingoogleplus

JavaScript

read more

SQL/T-SQL

read more

Umbraco CMS

read more

PowerShell

read more

Comments for this article