How to mock IConfiguration.GetValue

28,231

Solution 1

You can use an actual Configuration instance with in-memory data.

//Arrange
var inMemorySettings = new Dictionary<string, string> {
    {"TopLevelKey", "TopLevelValue"},
    {"SectionName:SomeKey", "SectionValue"},
    //...populate as needed for the test
};
IConfiguration configuration = new ConfigurationBuilder()
    .AddInMemoryCollection(inMemorySettings)
    .Build();
//...

Now it is a matter of using the configuration as desired to exercise the test

//...
string value = configuration.GetValue<string>("TopLevelKey");
string sectionValue = configuration.GetSection("SectionName").GetValue<string>("SomeKey");
//...

Reference: Memory Configuration Provider

Solution 2

I do not have idea about NSubstitute, but this is how we can do in Moq. Aproach is same in either cases.

You can Mock GetSection and return your Own IConfigurationSection.

This includes two steps.

1). Create a mock for IConfigurationSection (mockSection) & Setup .Value Property to return your desired config value.

2). Mock .GetSection on Mock<IConfiguration>, and return the above mockSection.Object

Mock<IConfigurationSection> mockSection = new Mock<IConfigurationSection>();
mockSection.Setup(x=>x.Value).Returns("ConfigValue");
Mock<IConfiguration> mockConfig = new Mock<IConfiguration>();
mockConfig.Setup(x=>x.GetSection(It.Is<string>(k=>k=="ConfigKey"))).Returns(mockSection.Object);

.GetValue() internally makes use of GetSection().

Solution 3

Mock IConfiguration

Mock config = new Mock();

setupGet

        config.SetupGet(x => x[It.Is<string>(s=>s == "DeviceTelemetryContainer")]).Returns("testConatiner");
        config.SetupGet(x => x[It.Is<string>(s => s == "ValidPowerStatus")]).Returns("On");

Solution 4

I could imagine in some rare scenarios it is needed but, in my humble opinion, most of the time, mocking IConfiguration highlight a code design flaw.

You should rely as much as possible to the option pattern to provide a strongly typed access to a part of your configuration. Also it will ease testing and make your code fail during startup if your application is misconfigured (instead than at runtime when the code reading IConfiguration is executed).

If you really(really) need to mock it then I would advice to not mock it but fake it with an in-memory configuration as explained in @Nkosi's answer

Share:
28,231
dudeNumber4
Author by

dudeNumber4

Long time C# developer. Pretty heavy TSQL developer as well. Some front end too.

Updated on November 14, 2021

Comments

  • dudeNumber4
    dudeNumber4 over 1 year

    I tried in vain to mock a top-level (not part of any section) configuration value (.NET Core's IConfiguration). For example, neither of these will work (using NSubstitute, but it would be the same with Moq or any mock package I believe):

    var config = Substitute.For<IConfiguration>();
    config.GetValue<string>(Arg.Any<string>()).Returns("TopLevelValue");
    config.GetValue<string>("TopLevelKey").Should().Be("TopLevelValue"); // nope
    // non generic overload
    config.GetValue(typeof(string), Arg.Any<string>()).Returns("TopLevelValue");
    config.GetValue(typeof(string), "TopLevelKey").Should().Be("TopLevelValue"); // nope
    

    In my case, I also need to call GetSection from this same config instance.

  • Tejashree
    Tejashree about 2 years
    I tried to set values for two keys in IConfiguration using two different mockSection objects. Still the value of the first key was overridden by the second value and the value of other key was 0. How to solve this problem?
  • Shekar Reddy
    Shekar Reddy about 2 years
    Make sure you use the right expression in k=>k=="configkey" istead of .it.isany.
  • Tejashree
    Tejashree about 2 years
    That's how I wrote: mockConfig.Setup(x => x.SetSection(It.Is<string>(k => k == "Key1"))).Returns(mocksection1.object); mockConfig.Setup(x => x.SetSection(It.Is<string>(k => k == "Key2"))).Returns(mocksection2.object);
  • Shekar Reddy
    Shekar Reddy about 2 years
    SetSection or GetSection?
  • jhoepken
    jhoepken almost 2 years
    Welcome to Stackoverflow. Can you please elaborate on your answer, to add some context?
  • Tony Mathew
    Tony Mathew almost 2 years
    I should have hit this post hours earlier, NSubstitute while returning nothing on IConfiguration.GetValue<string>, it breaks on GetValue<bool> with an InvalidOperationException: 'Failed to convert configuration value at '' to type 'System.Boolean'.' although the return value is specified correctly.
  • AaBa
    AaBa over 1 year
    This works well, only change I did here was to use constants i.e. config.SetupGet(x => x[Constants.SOME_KEY]).Returns("testConatiner"); Tx!
  • Regianni
    Regianni about 1 year
    Spot on - thanks
  • Ashu
    Ashu about 1 year
    for me mockSection.Setup(x=>x.Value).Returns("ConfigValue"); is throwing null object reference exception
  • Shekar Reddy
    Shekar Reddy about 1 year
    did you initialize mockSection
  • Diri Jianwei Guo
    Diri Jianwei Guo 11 months
    // example about how to configure a array setting. var inMemorySettings = new Dictionary<string, string> { {"SomeArrayKey:0", "value0"}, {"SomeArrayKey:1", "value1"}, {"SomeArrayKey:2", "value2"} };