.NET Core配置允许添加值(环境变量,json文件,命令行参数)的众多选项。
我只是想不通,找到一个如何通过代码填充它的答案。
我正在编写用于配置扩展方法的单元测试,并且我认为通过代码在单元测试中填充它比为每个测试加载专用的json文件容易。
我当前的代码:
[Fact]
public void Test_IsConfigured_Positive()
{
// test against this configuration
IConfiguration config = new ConfigurationBuilder()
// how to populate it via code
.Build();
// the extension method to test
Assert.True(config.IsConfigured());
}
更新:
一种特殊情况是“空部分”,它在json中看起来像这样。
{
"MySection": {
// the existence of the section activates something triggering IsConfigured to be true but does not overwrite any default value
}
}
更新2:
正如马修(Matthew)在评论中指出的那样,在json中有一个空白部分会产生与根本没有该部分相同的结果。我列举了一个例子,是的,就是这样。我期望其他行为是错误的。
那我该怎么办?我期望什么?
我正在为IConfiguration的2个扩展方法编写单元测试(实际上是因为Get ... Settings方法中的值绑定由于某些原因而无法工作(但这就是一个不同的主题)。它们看起来像这样:
public static bool IsService1Configured(this IConfiguration configuration)
{
return configuration.GetSection("Service1").Exists();
}
public static MyService1Settings GetService1Settings(this IConfiguration configuration)
{
if (!configuration.IsService1Configured()) return null;
MyService1Settings settings = new MyService1Settings();
configuration.Bind("Service1", settings);
return settings;
}
我的一个误解是,如果我在appsettings中放置一个空白部分,则IsService1Configured()
方法将返回true
(现在显然是错误的)。我期望的区别在于现在GetService1Settings()
方法返回一个空白部分,而不是我期望的null
具有所有默认值。
幸运的是,这对我仍然有效,因为我没有空白部分(或者现在知道我必须避免这些情况)。这只是我编写单元测试时遇到的一个理论案例。
再往前走(对于那些感兴趣的人)。
我该怎么用?基于配置的服务激活/停用。
我有一个应用程序,其中包含一个服务/编译了一些服务。根据部署情况,我需要完全激活/停用服务。这是因为某些(本地或测试设置)无法完全访问完整的基础结构(诸如缓存,指标等辅助服务)。我通过appsettings来做到这一点。如果配置了服务(config部分存在),则将添加该服务。如果config节不存在,则将不使用它。
摘录示例的完整代码如下。
MyService1Settings
和Service1
部分来激活/停用服务Service2
答案 0 :(得分:3)
我不想让我的应用程序类依赖于IConfiguration。相反,我创建了一个配置类来保存配置,并带有一个可以从IConfiguration进行初始化的构造函数,如下所示:
public class WidgetProcessorConfig
{
public int QueueLength { get; set; }
public WidgetProcessorConfig(IConfiguration configuration)
{
configuration.Bind("WidgetProcessor", this);
}
public WidgetProcessorConfig() { }
}
然后在您的ConfigureServices
中,您只需要执行以下操作:
services.AddSingleton<WidgetProcessorConfig>();
services.AddSingleton<WidgetProcessor>();
并进行测试:
var config = new WidgetProcessorConfig
{
QueueLength = 18
};
var widgetProcessor = new WidgetProcessor(config);
答案 1 :(得分:2)
您可以使用MemoryConfigurationBuilderExtensions
通过字典来提供它。
var myConfiguration = new Dictionary<string, string>
{
{"Key1", "Value1"},
{"Nested:Key1", "NestedValue1"},
{"Nested:Key2", "NestedValue2"}
}
var configuration = new ConfigurationBuilder()
.AddInMemoryCollection(myConfiguration)
.Build();
答案 2 :(得分:2)
我寻求的解决方案(至少可以回答问题标题!)是在解决方案import React from "react";
import { makeStyles } from '@material-ui/core/styles';
import {
Box,
Typography
} from '@material-ui/core';
const useStyles = makeStyles(theme => ({
root: {
padding: theme.spacing(0),
margin: theme.spacing(0)
}
}));
function ArticleBody(props) {
const classes = useStyles();
return (
<Box className={classes.root}>
<Typography
key={props.key}
color={props.color ? props.color : "default"}
align={props.align ? props.align : 'justify'}
variant={props.variant ? props.variant : 'body1'}
component="div"
dangerouslySetInnerHTML={{ __html: props.content }}
/>
</Box>
)
}
export default ArticleBody
中使用设置文件,并将其设置为“始终复制”。
testsettings.json
答案 3 :(得分:1)
AddInMemoryCollection
扩展方法会有帮助吗?
您可以将键值集合传递给它:
IEnumerable<KeyValuePair<String,String>>
包含测试所需的数据。
var builder = new ConfigurationBuilder();
builder.AddInMemoryCollection(new Dictionary<string, string>
{
{ "key", "value" }
});
答案 4 :(得分:1)
您可以使用以下技术来模拟IConfiguration.GetValue<T>(key)
扩展方法。
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);