使用Moq和Unity对Mock存储库对象进行单元测试的正确方法

Rob*_*ood 35 .net c# moq unity-container

在我的工作中,我们使用Moq进行模拟,使用Unity作为IOC容器.我对此很新,并且没有很多资源可以帮助我确定我应该使用的最佳实践.

现在,我有一组特定进程需要用来完成其工作的存储库接口(例如:IRepository1,IRepository2 ... IRepository4).

在实际代码中,我可以使用IOC容器并使用RegisterType()方法确定所有IRepository对象.

我试图找出能够测试需要4个提到的存储库的方法的最佳方法.

我想我可以只注册一个Unity IOC容器的新实例,并在每个模拟对象的容器上调用RegisterInstance,为每个模拟对象传递Mock.Object值.我试图使这个注册过程可重用,所以除了单元测试需要从存储库返回一些特定数据之外,我不必一遍又一遍地对每个单元测试做同样的事情.这就是问题所在......在模拟存储库上设置期望值的最佳做法是什么?好像我只是在Unity容器上调用RegisterType,我将失去对实际Mock对象的引用,并且无法覆盖行为.

Mar*_*ann 60

单元测试不应该使用容器.依赖注入(DI)分为两个阶段:

  1. 使用DI模式将依赖关系注入消费者.您不需要容器来执行此操作.
  2. 在应用程序的Composition Root中,使用DI容器(或穷人的DI)将所有组件连接在一起.

如何不使用任何DI容器进行单元测试

例如,考虑使用IRepository1的类.通过使用构造函数注入模式,我们可以使依赖项成为类的不变量.

public class SomeClass
{
    private readonly IRepository1 repository;

    public SomeClass(IRepository1 repository)
    {
        if (repository == null)
        {
            throw new ArgumentNullException("repository");
        }

        this.repository = repository;
    }

    // More members...
}
Run Code Online (Sandbox Code Playgroud)

请注意,readonly与Guard子句结合使用的关键字可确保repository在成功实例化实例时该字段不为null.

您不需要容器来创建MyClass的新实例.您可以使用Moq或其他Test Double直接从单元测试中执行此操作:

[TestMethod]
public void Test6()
{
    var repStub = new Mock<IRepository1>();
    var sut = new SomeClass(repStub.Object);
    // The rest of the test...
}
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参见此处

如何使用Unity进行单元测试

但是,如果您必须在测试中使用Unity,则可以创建容器并使用RegisterInstance方法:

[TestMethod]
public void Test7()
{
    var repMock = new Mock<IRepository1>();

    var container = new UnityContainer();
    container.RegisterInstance<IRepository1>(repMock.Object);

    var sut = container.Resolve<SomeClass>();
    // The rest of the test...
}
Run Code Online (Sandbox Code Playgroud)