在单元测试中获取配置
Get configuration in Unit Test
我不知道如何按照 IOptions 模式获取我正在使用的某些配置。
我要测试的服务是下一个:
private readonly Dictionary<ErrorType, ErrorObject> _errors;
public UserService(
...(Many services)...
IOptions<Dictionary<ErrorType, ErrorObject>> errors)
{
...
_errors = errors.Value;
}
其中 ErrorType 是一个枚举和 ErrorObject,一个具有我在 appsettings.json 中的错误格式的对象。就是这样:
{
"Errors": {
"UserNotFound": {
"ErrorCode": 101,
"Message": "User not found"
},
"WrongPassword": {
"ErrorCode": 102,
"Message": "Wrong password"
}
}
}
所以这工作得很好,但我现在的问题是我不知道如何实例化它、模拟它或在我的测试中注入它 class,因为即使我正在注入它我也可以' 以 class 的方式解决它,我总是得到一个空值。
我在测试夹具中像这样注入它(与我的真实注入模块相同):
serviceCollection.Configure<Dictionary<BusinessErrorType, BusinessErrorObject>>(x => Configuration.GetSection("Errors").Bind(x));
我必须正确地注入 IConfiguration 和所有错误,我只是无法为构造函数创建所需的字典。
在这里我得到了没有任何问题的错误:
IConfiguration Configuration = ioCModule.ServiceProvider.GetRequiredService<IConfiguration>();
var errorsConfig = Configuration.GetSection("Errors");
现在我得弄清楚要在这个声明中放些什么:
var _options = Options.Create<Dictionary<BusinessErrorType, BusinessErrorObject>>();
I injected it like this in the test fixture (same as in my real injection module):
您已尝试注入字典,而您的 class 期望获得选项。尝试注册并注入选项,很可能会成功。
And now I gotta figure out what to put in this declaration:
Options
对象只是一些随时可用的值的持有者,或者
没有什么。你必须构造 Options
对象
它的价值,或者不给它任何东西(并以空选项结束
目的)。如果使用不带任何参数的 Options.Create<Dict>()
,则会创建一个空对象,仅此而已。只需在此之前创建字典并将其传递给 Options
工厂.
var dict = new Dictionary<BusinessErrorType, BusinessErrorObject>();
dict.Add("UserNotFound", new BusinessErrorObject(....));
dict.Add("WrongPassword", new BusinessErrorObject(....));
var _options = Options.Create<Dictionary<BusinessErrorType, BusinessErrorObject>>(dict);
// now you have it: _options with some data inside
如果您指望将 Bind() 与 Options 一起使用 - 我怀疑它是否会像那样工作,因为 Bind 用于使用从设置文件读取的配置填充数据结构,而 Options 只是一个 shell,类似于 "Nullable<>",它的存在只是为了传递东西......但是我想你可以先创建一个字典,然后用配置填充它(即绑定)然后包装刚刚填写的字典使用 Options<>,然后在 IoC 中注册该 Options 对象,以便您的 UserService 可以获得其配置。但是,我不能 100% 确定 Bind 是否足够智能以填充通用词典。你需要自己测试一下,不幸的是我手头没有任何aspnetcore项目可以玩
EDIT/Sidenote:
我有点惊讶你在 单元测试 中 building/setting 完成了整个 IoC。创建单元测试时,您需要 cut/mock 尽可能多的依赖项。也就是说,没有IoC,可以引入另一组problems/failures/etc来测试。
我的意思是,我希望您的单元测试看起来像:
[Test]
public void FoobarizingTheBaz()
{
var mock1 = ....;
var mock2 = ....;
var mock3 = ....;
var ... = ....;
var mockN = ....;
var dict = new Dictionary<....>();
dict.Add(....);
dict.Add(....);
var mockOptions = Options.Create<...>(dict);
var tested = new UserService(
mock1, mock2, mock3, ... mockN, mockOptions
);
var result = tested.FoobarizeTheBaz();
// assert...
}
那是一个单元测试。只有被测试的对象被实例化,其余的被模拟,你只提供绝对必要的东西。当然,我不得不写很多 setup/mocks/etc 而不是依赖 IoC 来自动实现它们,但是一旦编写了模拟,你就可以将它们取出一些通用代码,测试 class init 、夹具等并重复使用它们。
我的意思是,没有 appsettings.json。无配置。无 IoC 等
如果您想测试有多少组件相互交互,那么它更像是一个集成测试。在这种情况下,您可能希望看到 this article 涉及在集成测试设置中使用自定义 appsettings.json 和 IOptions。但是,请注意,aspnetcore 中的 "integration tests" 通常意味着测试您的服务如何响应请求并检查响应,因此您将在本文中看到这一点。尽管如此,有关 IOptions 的部分应该有所帮助。
我不知道如何按照 IOptions 模式获取我正在使用的某些配置。
我要测试的服务是下一个:
private readonly Dictionary<ErrorType, ErrorObject> _errors;
public UserService(
...(Many services)...
IOptions<Dictionary<ErrorType, ErrorObject>> errors)
{
...
_errors = errors.Value;
}
其中 ErrorType 是一个枚举和 ErrorObject,一个具有我在 appsettings.json 中的错误格式的对象。就是这样:
{
"Errors": {
"UserNotFound": {
"ErrorCode": 101,
"Message": "User not found"
},
"WrongPassword": {
"ErrorCode": 102,
"Message": "Wrong password"
}
}
}
所以这工作得很好,但我现在的问题是我不知道如何实例化它、模拟它或在我的测试中注入它 class,因为即使我正在注入它我也可以' 以 class 的方式解决它,我总是得到一个空值。 我在测试夹具中像这样注入它(与我的真实注入模块相同):
serviceCollection.Configure<Dictionary<BusinessErrorType, BusinessErrorObject>>(x => Configuration.GetSection("Errors").Bind(x));
我必须正确地注入 IConfiguration 和所有错误,我只是无法为构造函数创建所需的字典。
在这里我得到了没有任何问题的错误:
IConfiguration Configuration = ioCModule.ServiceProvider.GetRequiredService<IConfiguration>();
var errorsConfig = Configuration.GetSection("Errors");
现在我得弄清楚要在这个声明中放些什么:
var _options = Options.Create<Dictionary<BusinessErrorType, BusinessErrorObject>>();
I injected it like this in the test fixture (same as in my real injection module):
您已尝试注入字典,而您的 class 期望获得选项。尝试注册并注入选项,很可能会成功。
And now I gotta figure out what to put in this declaration:
Options
对象只是一些随时可用的值的持有者,或者
没有什么。你必须构造 Options
对象
它的价值,或者不给它任何东西(并以空选项结束
目的)。如果使用不带任何参数的 Options.Create<Dict>()
,则会创建一个空对象,仅此而已。只需在此之前创建字典并将其传递给 Options
工厂.
var dict = new Dictionary<BusinessErrorType, BusinessErrorObject>();
dict.Add("UserNotFound", new BusinessErrorObject(....));
dict.Add("WrongPassword", new BusinessErrorObject(....));
var _options = Options.Create<Dictionary<BusinessErrorType, BusinessErrorObject>>(dict);
// now you have it: _options with some data inside
如果您指望将 Bind() 与 Options 一起使用 - 我怀疑它是否会像那样工作,因为 Bind 用于使用从设置文件读取的配置填充数据结构,而 Options 只是一个 shell,类似于 "Nullable<>",它的存在只是为了传递东西......但是我想你可以先创建一个字典,然后用配置填充它(即绑定)然后包装刚刚填写的字典使用 Options<>,然后在 IoC 中注册该 Options 对象,以便您的 UserService 可以获得其配置。但是,我不能 100% 确定 Bind 是否足够智能以填充通用词典。你需要自己测试一下,不幸的是我手头没有任何aspnetcore项目可以玩
EDIT/Sidenote:
我有点惊讶你在 单元测试 中 building/setting 完成了整个 IoC。创建单元测试时,您需要 cut/mock 尽可能多的依赖项。也就是说,没有IoC,可以引入另一组problems/failures/etc来测试。
我的意思是,我希望您的单元测试看起来像:
[Test]
public void FoobarizingTheBaz()
{
var mock1 = ....;
var mock2 = ....;
var mock3 = ....;
var ... = ....;
var mockN = ....;
var dict = new Dictionary<....>();
dict.Add(....);
dict.Add(....);
var mockOptions = Options.Create<...>(dict);
var tested = new UserService(
mock1, mock2, mock3, ... mockN, mockOptions
);
var result = tested.FoobarizeTheBaz();
// assert...
}
那是一个单元测试。只有被测试的对象被实例化,其余的被模拟,你只提供绝对必要的东西。当然,我不得不写很多 setup/mocks/etc 而不是依赖 IoC 来自动实现它们,但是一旦编写了模拟,你就可以将它们取出一些通用代码,测试 class init 、夹具等并重复使用它们。
我的意思是,没有 appsettings.json。无配置。无 IoC 等
如果您想测试有多少组件相互交互,那么它更像是一个集成测试。在这种情况下,您可能希望看到 this article 涉及在集成测试设置中使用自定义 appsettings.json 和 IOptions。但是,请注意,aspnetcore 中的 "integration tests" 通常意味着测试您的服务如何响应请求并检查响应,因此您将在本文中看到这一点。尽管如此,有关 IOptions 的部分应该有所帮助。