【问题标题】:How to setup Mock of IConfigurationRoot to return value [duplicate]如何设置 IConfigurationRoot 的 Mock 以返回值 [重复]
【发布时间】:2017-09-22 22:35:06
【问题描述】:

我使用 IConfigurationRoute 来访问这样的目录。

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

_config 是在构造函数中注入的 IConfigurationRoot。

我尝试了以下方式来模拟它。

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

问题是在运行测试时 Xunit 抛出异常说

"System.NotSupportedException : 表达式引用了一个方法 不属于模拟对象”

我该如何解决这个问题?

【问题讨论】:

  • 您正在尝试模拟扩展方法,这是 Moq 无法做到的。
  • 感谢 cmets。但是周围的方法是什么,我的意思是这个行业的人是怎么做的?我无法在 .net 核心中使用 Fakes。我找不到解决方案,我是 .net 新手。

标签: c# unit-testing asp.net-core moq xunit.net


【解决方案1】:

我使用 SetupGet 方法如下。它对我有用,希望对您有所帮助。

_configurationRoot = new Mock<IConfigurationRoot>();
_configurationRoot.SetupGet(x => x[It.IsAny<string>()]).Returns("the string you want to return");

【讨论】:

  • 简单有效,正是我想要的!
  • ConfigurationBuilder 存在,你为什么要对自己这样做?
  • 这似乎不起作用。另一种方法是根本不模拟: builder.AddInMemoryCollection(new Dictionary { { "ConnectionStrings:DB", "MyConnection" }, { "MyKey", "MyValue" } }); var config = builder.Build();
  • @PeterRitchie ConfigurationBuilder 存在,但需要包含 appsettings.json 文件并确保它被复制。对于像这样的简单场景,模拟它更容易 imo
  • 在很多情况下都不起作用,比如使用.Get&lt;T&gt;扩展方法时。
【解决方案2】:
  1. 将 appSettings.json 复制到您的测试项目根目录,并将其属性标记为内容,如果较新则复制。

  2. var builder = new ConfigurationBuilder()
          .SetBasePath(Directory.GetCurrentDirectory())
          .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
          .AddEnvironmentVariables();
    ConfigurationManager.Configuration = builder.Build();
    
  3. ConfigurationManager 是一个类,它有一个静态属性 Configuration。这样整个应用程序就可以作为 ConfigurationManager.Configuration[]

  4. 访问它

【讨论】:

    【解决方案3】:

    我认为您这样做的方式是构建可模拟的代理扩展方法,并改为使用这些方法。本地扩展方法可以覆盖外部方法,因此您可以创建自己的扩展类:

    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);
    }
    

    然后,设置您的代理:

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

    现在,在每个要使用可模拟扩展方法的类中,添加一个静态构造函数:

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

    或者

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

    清洗、冲洗、重复您需要使用的每种扩展方法。可以在这里找到更多解释: http://blogs.clariusconsulting.net/kzu/how-to-design-a-unit-testable-domain-model-with-entity-framework-code-first/

    此外,如果它有帮助,您还可以模拟字典的 getter:

    mockConfigurationRoot.SetupGet(m => m["ConnectionStrings:Repository"]).Returns("bogus");
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-03
      • 1970-01-01
      • 2012-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-27
      • 2015-06-19
      相关资源
      最近更新 更多