使用IoC进行单元测试


97

如何将IoC容器用于单元测试?使用IoC在大型解决方案(50多个项目)中管理模拟是否有用?有经验吗?是否有任何在单元测试中很好地使用它的C#库?


7
@Mark Seemann会很谦虚地指出这一点,但是,如果您对此问题感兴趣,则至少应了解AutoFixture
Ruben Bartelink 2011年

1
Miguel Castro对Vimeo上的DI和模拟
GregC 2014年

Answers:


131

一般而言,单元测试不需要DI容器,因为单元测试全部与分离职责有关。

考虑使用构造函数注入的类

public MyClass(IMyDependency dep) { }

在您的整个应用程序中,可能隐藏了一个巨大的依赖图IMyDependency,但是在单元测试中,您将其全部压平为一个 Test Double

您可以使用Moq或RhinoMocks之类的动态模拟来生成Test Double,但这不是必需的。

var dep = new Mock<IMyDependency>().Object;
var sut = new MyClass(dep);

在某些情况下,可以使用自动模拟容器,但是您不需要使用生产应用程序使用的同一DI容器。


13
同意...除非测试目标将IoC容器作为依赖项,否则您的测试不需要它们...在进行单元测试时,您将删除大多数对象图。
安德森·埃姆斯(Emerson Imes)2009年

4
@Mark Seemann这很有道理...但是集成测试呢?即,我玩过UI测试,当我不得不共享合成根时,我遇到了情况。任何意见?
阿尼斯·拉普萨

5
@Arnis L .:对于集成测试,它的重要性不那么高。您可以选择使用DI容器连接组件,但是,如果这样,您可能需要的容器配置与完整应用程序中的配置不同-除非执行皮下测试或完整系统测试,否则您可以重用容器的应用程序配置。
Mark Seemann 2010年

参阅

18

Ioc容器如何用于单元测试?

IoC将实施编程范例,从而使隔离(即使用模拟)的单元测试更加容易:使用接口,不使用new(),不使用单例...

但是,使用IoC容器进行测试并不是真正的要求,它仅提供了一些功能,例如注入模拟,但您可以手动进行。

使用IoC在大型解决方案(50多个项目)中管理模拟是否有用?

我不确定使用IoC管理模拟是什么意思。无论如何,在进行测试时,IoC容器通常不仅仅可以注入模拟。而且,如果您拥有使重构成为可能的不错的IDE支持,为什么不使用它呢?

有经验吗?

是的,在一个庞大的解决方案上,您比以往任何时候都需要一个不易出错且不利于重构的解决方案(即通过类型安全的IoC容器或良好的IDE支持)。


17

我经常在测试中使用IoC容器。当然,它们并不是纯粹的“单元测试”。国际海事组织他们更加BDDish并且促进重构。有测试可以使您有信心进行重构。编写不佳的测试就像在代码中注入水泥。

考虑以下:

[TestFixture]
public class ImageGalleryFixture : ContainerWiredFixture
{
    [Test]
    public void Should_save_image()
    {
        container.ConfigureMockFor<IFileRepository>()
            .Setup(r => r.Create(It.IsAny<IFile>()))
            .Verifiable();

        AddToGallery(new RequestWithRealFile());

        container.VerifyMockFor<IFileRepository>();
    }

    private void AddToGallery(AddBusinessImage request)
    {
        container.Resolve<BusinessPublisher>().Consume(request);
    }
}

将图像添加到图库时,会发生几件事。调整图像大小,生成缩略图,并将文件存储在AmazonS3上。通过使用容器,我可以更轻松地仅隔离要测试的行为,在这种情况下,这是持久的部分。

使用此技术时,自动模拟容器扩展会派上用场:http : //www.agileatwork.com/auto-mocking-unity-container-extension/


8
+1表示“就像将水泥倒入您的代码中”。我一直都在使用它。
Andrew Shepherd

2

使用能够解析未注册/未知服务(例如SimpleInjectorDryIoc)的容器(属于我的)可以为尚未实现的接口返回。

这意味着您可以从第一个简单的实现及其模拟的依赖项开始开发,并在进行过程中将其替换为真实的东西。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.