单元测试:unitycontainer

本文关键字:unitycontainer 单元测试 | 更新日期: 2023-09-27 18:18:45

我有一个使用Unity进行DI的应用程序,但是我在编写单元测试时遇到了一点障碍。在我的几个业务层方法中,我有类似于下面的代码:

var obj = container.Resolve<ISomeObj>();

这要么是一个将最终传递给数据库的内存对象,要么是一个将最终传递给客户端的内存对象。但问题是,RhinoMocks(似乎)无法正确地模拟容器,因此可以这样做:

 mockContainer = MockRepository.GenerateMock<IUnityContainer>();
 mockContainer.Expect(x => x.Resolve<ISomeObj>())
            .Return(mockObj);

在这里得到一个异常似乎是有意义的,因为容器实际上是空的,但我没有看到一个直接的方法来解决这个问题。我曾经考虑过用包装器抽象容器来解决这个问题,但这似乎有点过头了。

任何想法或建议都非常感谢!

——编辑——

自从Yacoub发表了他的答案后,我一直在阅读一些关于服务定位器(反)模式的文章,虽然它似乎被普遍接受为一种反模式,但我还没有找到关于如何处理poco的答案。

用我上面的例子,我的问题的一般答案似乎是这样做:

public class Foo()
{
    private ISomeObj someObj;
    public Foo(ISomeObj injectObj)
    {
        someObj = injectObj;
    }
}

我想我对这种方法唯一的抱怨是它会(潜在地)使构造函数"忙碌",

public class Foo()
{
    public Foo(ISomeService injectSvc, ISomeObj injectObj, ISomeObj2 injectObj2, ISomeObj3 injectObj3)
    {
        ...
    }
}

此外,除非我遗漏了什么,否则我需要一种方法来重新初始化给定的实例以供重用。含义:如果MethodA()和MethodB()都消耗ISomeObj,当MethodA()完成ISomeObj时,我需要以某种方式重新初始化ISomeObj中的所有字段,以便MethodB()可以做它的工作。

解决这个问题的"最佳"方法是什么?

单元测试:unitycontainer

您所做的(使用容器从您的业务层方法内部解析对象)称为服务定位,被认为是一种反模式。您可能需要考虑重构以使用构造函数注入。如果你这样做了,那么你就不需要在单元测试中使用容器了。

话虽如此,以下是您可以在不进行重构的情况下做的事情:不要模拟容器。相反,应该使用真正的容器,并向容器注册模拟实例,如下所示:

container.RegisterInstance<ISomeObj>(mockObj); //mockObj is the mocking object that implements ISomeObj

对该接口(ISomeObj)执行的所有解析操作将返回相同的实例。

如果您需要能够为每个解析操作获得一个新的实例,您可以这样做:

container.RegisterType<ISomeObj>(new InjectionFactory(x => GenerateMock()));

其中GenerateMock是创建模拟对象的方法。您可以使用使用RhinoMocks创建模拟的代码替换此调用。