Populate IConfiguration for unit tests
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" }
});