【问题标题】:Mocking vs IoC container in unit testing单元测试中的模拟与 IoC 容器
【发布时间】:2015-01-20 18:49:45
【问题描述】:

TL;DR - 我将“集成测试”与“单元测试”混为一谈。

我对单元测试和 IoC 容器感到困惑...... :(

我已阅读 this article 关于在单元测试中不应使用 IoC 容器的方法。这似乎是许多人对 SO 和其他各种文章的看法。在单元测试中,您可以测试您的方法,但应该模拟任何依赖项。

通过上述文章,我想问一些问题。

换句话说,如果组件 A 调用组件 B,那么从单元测试的角度来看,我们不能让组件 A 调用组件 B 的实际实现。相反,必须模拟组件 B。

但是……为什么?

我们使用假组件 B 而不是真正的组件 B,因此 1) 我们的测试可以 不依赖任何其他类中的代码,2) 组件 B 返回相同 数据每次和 3)我们可以拦截对组件 B 的调用,所以我们可以 检查调用方式和时间。

广告。 1) 我现在没有进行测试,而是在真正的应用程序中会发生什么,我现在正在无理地伪造组件 B....为了什么目的?这样我就知道组件 A 是以隔离方式进行测试的?但是我的应用程序同时使用了这两个组件,并且这些组件一起工作。

引用暗示我必须单独对组件 A 和组件 B 进行单元测试,并且我应该只测试组件的业务。

但这破坏了自动化测试的全部意义,我在其中创建关于应用程序功能的保证,即应用程序不会崩溃,同时使用这两个组件。与孤立环境中的内部单元无关。

广告。 2) 我知道我测试的所有内容都是确定性的,对于各种输入 X,它会返回一些 Y,或者抛出异常或其他东西 - 这就是我实际测试的内容。

广告。 3) 我可以想象这在复杂的测试中是有意义的......

对我来说,如果组件 B 是第 3 方代码,我无法在不复制大量代码的情况下轻松地在测试类中创建...或者如果我有理由不调用组件 B 的实际实现,那么嘲笑是有意义的因为不是真的想对数据库进行实际更改,实际上不是发送电子邮件,实际上不是移动/写入/读取/删除文件等。

但是,我会使用不同的 IoC 容器进行模拟,而不是 Bind<ISomeService>().To<BusinessImplementation>() 我会写 Bind<ISomeService>().To<TestImplementation()(Ninject 中的代码示例)

通过测试,我想对应用程序做出保证,在部署的应用程序中会发生什么,并且通过在没有充分理由的情况下模拟依赖关系,我在一个非常不同的环境中进行测试。

当应用程序启动时,它使用我编写的 IoC 容器。应用程序的依赖关系使用 IoC 容器解决。


我认为我可能对某些事情有误,但我还看不到...

【问题讨论】:

  • 单元测试!= 集成测试,基本上。我不喜欢教条主义 - 通常值得伪造(不一定是嘲笑)难以设置或需要很长时间的依赖项,例如数据库,但在其他一些情况下,我认为使用真实的东西很好。另请注意,根据您的 IoC 容器,您可能希望使用它来查找所有依赖项,但具有适当的“测试”配置而不是“生产”配置。

标签: c# unit-testing dependency-injection automated-tests ioc-container


【解决方案1】:

目的不是要替换将从更高级别测试模块的集成测试。单元测试旨在单独测试一个离散类,主要是为了确认该类的设计和编码是完整的。

【讨论】:

  • 集成测试。那是缺少的部分。学到了一些新东西。谢谢你:)
  • 没问题,很高兴我能帮上忙
【解决方案2】:

相反,必须模拟组件 B。但是……为什么?

简单地说,单元测试是为了测试一个单一的功能。如果测试失败,是因为组件A还是组件B?

测试是关于什么的?

组件 B 是否通过了自己的一系列测试?

将组件 A 与 B 的真实实例一起测试不会回答这些问题。相反,它会提出比它实际回答的问题更多的问题。

我现在不是测试,而是在实际应用程序中会发生什么,我现在正在无理地伪造组件 B....为了什么目的?

实际上,它是将组件 A 与组件 B 隔离开来,以便任何行为不端仅由组件 A 引起。这可以降低测试的复杂性并明确您在做什么,因此单元测试中的“单元” .

如果组件 B 是第 3 方代码,我无法在不复制大量代码的情况下轻松地在测试类中创建,那么嘲笑是有意义的...

基本上,您可以这样做。这不仅在单元测试中很重要。相反,使用依赖注入,我们应该模拟每个引用类型,以便将组件 A 与任何外部影响隔离开来,即确保组件 A 的行为符合预期。

您想用组件 B 的真实实例测试组件 A 的那一天实际上并不是您进行单元测试的那一天,但这称为集成测试,这些测试应在您确定每个组件的行为之后编写以单一的形式。

请看这个问题的答案:Unit Testing or Functional Testing?

附带说明,不建议在单元测试中使用 DI 容器。它使测试变得复杂,没有附加价值。

【讨论】:

  • 那么,单元测试是由开发人员编写的,而集成测试是由谁编写的?
  • @pixel 这也是每个开发人员的责任,以确保所有内容都以无害的方式与其他软件集成。
猜你喜欢
  • 2011-04-27
  • 1970-01-01
  • 2012-05-02
  • 1970-01-01
  • 1970-01-01
  • 2013-09-05
  • 1970-01-01
  • 2010-09-30
  • 2019-12-13
相关资源
最近更新 更多