Solution 1:

You can use MemoryConfigurationBuilderExtensions to provide it via a dictionary.

using Microsoft.Extensions.Configuration;

var myConfiguration = new Dictionary<string, string>
{
    {"Key1", "Value1"},
    {"Nested:Key1", "NestedValue1"},
    {"Nested:Key2", "NestedValue2"}
};

var configuration = new ConfigurationBuilder()
    .AddInMemoryCollection(myConfiguration)
    .Build();

The equivalent JSON would be:

{
  "Key1": "Value1",
  "Nested": {
    "Key1": "NestedValue1",
    "Key2": "NestedValue2"
  }
}

The equivalent Environment Variables would be (assuming no prefix / case insensitive):

Key1=Value1
Nested__Key1=NestedValue1
Nested__Key2=NestedValue2

The equivalent Command Line parameters would be:

dotnet <myapp.dll> -- --Key1=Value1 --Nested:Key1=NestedValue1 --Nested:Key2=NestedValue2

Solution 2:

The solution I went for (which answers the question title at least!) is to use a settings file in the solution testsettings.json and set it to "Copy Always".

private IConfiguration _config;

public UnitTestManager()
{
    IServiceCollection services = new ServiceCollection();

    services.AddSingleton<IConfiguration>(Configuration);
}

public IConfiguration Configuration
{
    get
    {
        if (_config == null)
        {
            var builder = new ConfigurationBuilder().AddJsonFile($"testsettings.json", optional: false);
            _config = builder.Build();
        }

        return _config;
    }
}

Solution 3:

You can use the following technique to mock IConfiguration.GetValue<T>(key) extension method.

var configuration = new Mock<IConfiguration>();
var configSection = new Mock<IConfigurationSection>();

configSection.Setup(x => x.Value).Returns("fake value");
configuration.Setup(x => x.GetSection("MySection")).Returns(configSection.Object);
//OR
configuration.Setup(x => x.GetSection("MySection:Value")).Returns(configSection.Object);

Solution 4:

I prefer not to have my application classes dependent on IConfiguration. Instead, I create a configuration class to hold the config, with a constructor that can initialise it from IConfiguration, like this:

public class WidgetProcessorConfig
{
    public int QueueLength { get; set; }
    public WidgetProcessorConfig(IConfiguration configuration)
    {
        configuration.Bind("WidgetProcessor", this);
    }
    public WidgetProcessorConfig() { }
}

then in your ConfigureServices, you just have to do:

services.AddSingleton<WidgetProcessorConfig>();
services.AddSingleton<WidgetProcessor>();

and for testing:

var config = new WidgetProcessorConfig
{
    QueueLength = 18
};
var widgetProcessor = new WidgetProcessor(config);

Solution 5:

Would AddInMemoryCollection extension method help?

You can pass a key-value collection into it: IEnumerable<KeyValuePair<String,String>> with the data you might need for a test.

var builder = new ConfigurationBuilder();

builder.AddInMemoryCollection(new Dictionary<string, string>
{
     { "key", "value" }
});