使用 IoC 进行单元测试

Posted

技术标签:

【中文标题】使用 IoC 进行单元测试【英文标题】:Using IoC for Unit Testing 【发布时间】:2010-11-30 18:03:58 【问题描述】:

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

【问题讨论】:

@Mark Seemann 太谦虚了,无法指出,但如果你对这个问题感兴趣,你至少应该知道AutoFixture Miguel Castro 对 DI 和模拟 Vimeo 之间的关系进行了很好的讨论:vimeo.com/68390510 【参考方案1】:

一般来说,DI 容器对于单元测试来说不是必需的,因为单元测试就是为了分离职责。

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

public MyClass(IMyDependency dep)  

在您的整个应用程序中,IMyDependency 后面可能隐藏着一个巨大的依赖关系图,但在单元测试中,您将其全部展平为一个 Test Double。

您可以使用 Moq 或 RhinoMocks 等动态模拟来生成测试替身,但这不是必需的。

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

在某些情况下,auto-mocking container 可能会很好,但您不需要使用与生产应用程序相同的 DI 容器。

【讨论】:

同意...除非测试目标具有 IoC 容器 as 依赖项,否则您的测试不应该需要它们...您将删除大部分进行单元测试时使用对象图。 @Mark Seemann 这很有道理......但是集成测试呢?即,我玩过 UI 测试,当我不得不共享组合根时,我遇到了这种情况。有cmets吗? @Arnis L.:对于集成测试,它不太重要。您可以选择使用 DI 容器来连接组件,但如果是这样,您可能需要与完整应用程序不同的容器配置 - 除非您执行皮下测试或完整系统测试,在这种情况下您可以重用应用程序对 Container 的配置。 参考 msdn 杂志测试替身:download.microsoft.com/download/3/A/7/…【参考方案2】:

我经常在测试中使用 IoC 容器。当然,它们不是纯粹意义上的“单元测试”。 IMO 他们更 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/

【讨论】:

+1 表示“就像在代码中倒水泥一样”。我一直在使用它。【参考方案3】:

如何使用 Ioc 容器进行单元测试?

IoC 将强制执行编程范式,这将使孤立的单元测试(即使用模拟)更容易:使用接口,没有 new(),没有单例......

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

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

我不确定您所说的使用 IoC 管理模拟是什么意思。无论如何,在测试方面,IoC 容器通常可以做的不仅仅是注入模拟。如果您有良好的 IDE 支持,可以进行重构,为什么不使用它呢?

有什么经验吗?

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

【讨论】:

【参考方案4】:

使用能够解析未注册/未知服务的容器,例如 SimpleInjector、DryIoc(它的我的),可以为尚未实现的接口返回模拟。

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

【讨论】:

以上是关于使用 IoC 进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章

Autofac 通过 PreserveExistingDefaults 解决单元测试 Fake 对象被覆盖

Spring 测试

SpringJunit加载Spring容器作单元测试(转)

Junit加载Spring容器作单元测试

SpringJunit加载Spring容器作单元测试

Android怎样进行单元测试