我有一个 PRISM 应用程序,它由几个模块(IModule)组成,其中引导程序将每个模块传递给 DI 容器,以便每个模块都能够注入/解析服务。这意味着每个模块都有自己的“组合根”,其中类型被注入/解析,我想知道关于单元测试的最佳实践是什么。
例如,假设我有一个资源模块,它负责创建和注册从各种数据源获取数据的服务。假设我实现了 IModule.Initialize 方法,如下所示:
void Initialize()
{
ISomeDataService someDataService = _container.Resolve<SomeDataService>();
someDataService.Connect();
_container.RegisterInstance<ISomeDataService>(someDataService);
}
Resources 模块创建 SomeDataService 的一个实例,打开一个连接,并注册它以便其他模块可以使用它。注意:这实际上不是我的做法,这只是为了快速说明。
现在从单元测试的角度来看,我如何测试 Initialize 方法?我想在这里测试两件事:
ISomeDataService.Connect()
方法被调用。IUnityContainer.RegisterInstance
正在调用并提供正确的服务。
由于Initialize()
负责实际创建具体类型并注册它们,因此在为它提供我自己的ISomeDataService
模拟时似乎我很不走运。现在它确实尝试解决具体类型SomeDataService
(这与做的事情基本相同new SomeDataService()
),所以我可以尝试模拟具体类型SomeDataService
并覆盖我想要测试的方法,但是当具体类型有副作用时这会成为一个问题例如 ChannelFactory 在实例化后立即尝试解析有效的 WCF 绑定,并在失败时抛出异常。我可以通过为它提供有效的绑定来避免这种失败,但我认为单元测试不应该依赖于这些东西。
有什么建议吗?我的一个想法如下:
void Initialize()
{
if (_container.IsRegistered<ISomeDataService>())
{
someDataService = _container.Resolve<ISomeDataService>();
}
else
{
someDataService = _container.Resolve<SomeDataService>(); // or new SomeDataService()
}
_container.RegisterInstance<ISomeDataService>(someDataService);
someDataService.Connect();
}
这样做我可以模拟 ISomeDataService 而不是具体类型 SomeDataService 一切都很好,但我不知道这是否是正确的方法......我确定我做错了,必须有其他方法.