我正在运行Windows服务中托管的WCF服务; WCF服务的依赖关系是通过Unity注入的,这一切都很好。因此,该服务也很容易编写单元测试。
最近,我在服务中添加了一些功能,它使用OperationContext来检查传入的消息。不幸的是,由于微软对密封和/或静态类的缺乏以及缺乏接口和/或虚拟方法,这使得服务的可测试性降低了。
所以在这种情况下,我转向了.NET'ers最喜欢的工具,一个包装类。由于这是一个常见问题,有人already done the hard work for us。因此,这为我的WCF服务添加了一个新的依赖项,这是IOperationContext的一个实现。这对我的单元测试来说没有问题,NSubstitute是我选择的模拟框架(如Moq,但没有.Object
的诅咒)。
但是,当我尝试启动真实服务时,我遇到以下问题 - 正在进行包装的OperationContext在IoC容器注册完成时尚未初始化。我的初始化代码(在这里使用Unity)是:
container.RegisterType<IOperationContext, OperationContextWrapper>(new InjectionConstructor(OperationContext.Current));
但此时OperationContext.Current
为null
,因此Unity会立即抛出异常,而我在40岁之前退休的梦想也会消失。
所以,问题是:你如何让WCF与DI和OperationContext
包裹得很好?
答案 0 :(得分:2)
也许我不理解,但我不确定为什么要将OperationContext.Current注入到包装器中。如果OperationContextWrapper正在包装OperationContext,那么为什么不让它的实现直接与OperationContext.Current进行交互呢?我假设你试图保持可测试的代码不是OperationContextWrapper,而是通过IOperationContext接口依赖它的代码?那么谁在乎OperationContextWrapper的作用呢?
答案 1 :(得分:1)
OperationContext.Current
是一个可设置的属性。您可以将测试初始化更改为
OperationContext.Current = new OperationContextWrapper();
并以这种方式工作?如果你需要统一,你也可以:
var oc = new OperationContextWrapper();
OperationContext.Current = oc;
container.RegisterInstance<IOperationContext>(oc);
答案 2 :(得分:1)
您还可以使用Microsoft Fakes:
using (ShimsContext.Create())
{
ShimOperationContext shimOperationContext = new
ShimOperationContext(); shimOperationContext.SessionIdGet = () => "sessionId";
OperationContext.Current = shimOperationContext;
}