微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何模拟IConfiguration.GetValue 模拟 IConfiguration设置获取

如何解决如何模拟IConfiguration.GetValue 模拟 IConfiguration设置获取

我徒劳地尝试模拟顶级(而不是任何部分的一部分)配置值(.Net Core的IConfiguration)。例如,这些都不起作用(使用NSubstitute,但是对于moq或我相信的任何模拟包都一样):

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

就我而言,我还需要从同一配置实例调用GetSection

解决方法

您可以将实际的Configuration实例与内存数据一起使用。

//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();


//...

现在只需根据需要使用配置即可进行测试

//...

string value = configuration.GetValue<string>("TopLevelKey");

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

//...

参考Memory Configuration Provider

,

您可以模拟 GetSection 并返回您自己的 IConfigurationSection。

这包括两个步骤。

1)。为 IConfigurationSection (mockSection) 和设置 .Value 属性创建一个模拟以返回您想要的配置值。

2)。在 .GetSection 上模拟 Mock<IConfiguration>,并返回上面的 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() 在内部使用 GetSection()。

,

IConfiguration.GetSection<T>必须间接模拟。我不完全理解为什么,因为IIUC NSubstitute创建了它自己对正在运行的接口(在内存程序集中)进行模拟的自己的实现。但这似乎是唯一的方法。包括顶级部分和常规部分。

var config = Substitute.For<IConfiguration>();
var configSection = Substitute.For<IConfigurationSection>();
var configSubSection = Substitute.For<IConfigurationSection>();
configSubSection.Key.Returns("SubsectionKey");
configSubSection.Value.Returns("SubsectionValue");
configSection.GetSection(Arg.Is("SubsectionKey")).Returns(configSubSection);
config.GetSection(Arg.Is("TopLevelSectionName")).Returns(configSection);

var topLevelSection = Substitute.For<IConfigurationSection>();
topLevelSection.Value.Returns("TopLevelValue");
topLevelSection.Key.Returns("TopLevelKey");
config.GetSection(Arg.Is<string>(key => key != "TopLevelSectionName")).Returns(topLevelSection);

// GetValue mocked indirectly.
config.GetValue<string>("TopLevelKey").Should().Be("TopLevelValue");
config.GetSection("TopLevelSectionName").GetSection("SubsectionKey").Value.Should().Be("SubsectionValue");
,

模拟 IConfiguration

模拟配置 = new Mock();

设置获取

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

我可以想象在一些罕见的情况下它是需要的,但以我的拙见,大多数时候,模拟 IConfiguration 突出了代码设计缺陷。

您应该尽可能地依赖选项模式来提供对部分配置的强类型访问。如果您的应用程序配置错误(而不是在执行读取 IConfiguration 的代码时在运行时),它还可以简化测试并使您的代码在启动期间失败。

如果您真的(真的)需要模拟它,那么我建议不要模拟它,而是使用内存配置来模拟它,如@Nkosi 的 answer

中所述 ,
//Arrange
var inMemorySettings = new Dictionary<string,string> {
    {"InformationValue","AnyJSON"},};

IConfiguration configuration = new ConfigurationBuilder()
    .AddInMemoryCollection(inMemorySettings)
    .Build();


//...

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。