How to setup Mock of IConfigurationRoot to return value [duplicate]
Asked Answered
B

3

27

I have used IConfigurationRoute to access a directory like this.

if (type == "error") directory = _config.GetValue<string>("Directories:SomeDirectory");

_config is IConfigurationRoot injected in the constructor.

I tried the following way to mock it.

        var mockConfigurationRoot = new Mock<IConfigurationRoot>();
        mockConfigurationRoot.Setup(c => c.GetValue<string>("Directories: SomeDirectory"))
            .Returns("SomeDirectory")
            .Verifiable();
        var config = mockConfigurationRoot.Object;

The issue is while running the test Xunit throws the exception saying

"System.NotSupportedException : Expression references a method that does not belong to the mocked object"

How can I solve this issue?

Battleax answered 25/4, 2017 at 18:48 Comment(3)
See this question.Submerge
You are trying to mock an extension method, which Moq is unable to do.Exempt
Thanks for the comments. But what is the way around, I mean how are people in the industry doing it? I was not able to use Fakes in .net core. I could not find solution, I'm new to .net.Battleax
S
43

I did it using the SetupGet method as follows. It works for me, hope it helps.

_configurationRoot = new Mock<IConfigurationRoot>();
_configurationRoot.SetupGet(x => x[It.IsAny<string>()]).Returns("the string you want to return");
Sothena answered 28/11, 2017 at 0:36 Comment(6)
Simple and effective, just what I was looking for!Graeme
ConfigurationBuilder exists, why would you want to do that to yourself?Shugart
I tried to mock the "IConfiguration" to get the "GetConnectionString" method with my own connection string. It didn't work.Loki
This does not appear to work. An alternative is not to mock at all: builder.AddInMemoryCollection(new Dictionary<string, string> { { "ConnectionStrings:DB", "MyConnection" }, { "MyKey", "MyValue" } }); var config = builder.Build();Adjoin
@PeterRitchie ConfigurationBuilder exists but requires including the appsettings.json file and ensuring it gets copied. Mocking it is easier for simple scenarios like this imoRaimund
Won't work in many cases, like when using .Get<T> extension method.Ferbam
P
13
  1. Copy the appSettings.json to your Test project root directory and mark it's property as Content and Copy if newer.

  2. var builder = new ConfigurationBuilder()
          .SetBasePath(Directory.GetCurrentDirectory())
          .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
          .AddEnvironmentVariables();
    ConfigurationManager.Configuration = builder.Build();
    
  3. ConfigurationManager is a class and it has a static property Configuration. This way the whole application can just access it as ConfigurationManager.Configuration[]

Powerdive answered 5/7, 2017 at 18:50 Comment(0)
K
2

I think the way you'd do it is to build mockable proxy extension methods, and use those, instead. Local extension methods can override external methods, so you can create your own extensions class:

public static class ConfigurationExtensions
{
    public static IConfigurationProxy Proxy = new ConfigurationProxy();
    public static T GetValue<T>(this IConfigurationRoot config, string key) => Proxy.GetValue<T>(config, key);
}

Then, setup your proxy:

public class ConfigurationProxy : IConfigurationProxy
{
    public T GetValue<T>(IConfigurationRoot config, string key) => config.GetValue<T>(key);
}

Now, in each class where you want to use mockable extension methods, add a static constructor:

static MyClass()
{
    ConfigurationExtensions.Proxy = new ConfigurationProxy();
}

Or

static MyClass_Tests()
{
    ConfigurationExtensions.Proxy = Mock.Of<IConfigurationProxy>();
}

Wash, rinse, repeat for each extension method you need to use. More explanation can be found, here: http://blogs.clariusconsulting.net/kzu/how-to-design-a-unit-testable-domain-model-with-entity-framework-code-first/

Also, in case its helpful, you can also mock the dictionary's getter:

mockConfigurationRoot.SetupGet(m => m["ConnectionStrings:Repository"]).Returns("bogus");
Kataway answered 12/10, 2017 at 16:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.