使用 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 进行单元测试的主要内容,如果未能解决你的问题,请参考以下文章