【问题标题】:MVC 5 Unit tests vs integration testsMVC 5 单元测试与集成测试
【发布时间】:2015-07-01 21:57:48
【问题描述】:

我目前正在使用 Entity Framework 5 进行 MVC 5 项目(我可能很快会切换到 6)。我首先使用数据库,然后将 MySQL 与现有数据库(大约 40 个表)一起使用。这个项目最初是作为“概念验证”的,现在我的公司决定使用我正在开发的软件。我在测试部分苦苦挣扎。

我的第一个想法是主要使用集成测试。这样我觉得我可以测试我的代码以及我的底层数据库。我创建了一个脚本,将现有数据库模式转储到 MySQL 中的“测试数据库”中。我总是从一个没有数据的干净数据库开始我的测试,并为每个测试创建/删除一些数据。问题是我运行测试需要相当长的时间(我经常运行测试)。

我正在考虑用单元测试替换我的集成测试,以加快运行它们的时间。我会“删除”测试数据库,而只使用模拟。我已经测试了一些方法,似乎效果很好,但我想知道:

  1. 您是否认为模拟我的数据库可以“隐藏”仅当我的代码针对真实数据库运行时才会出现的错误?请注意,我不想测试 Entity Framework(我确信微软的优秀人员在这方面做得很好),但是我的代码能否很好地针对模拟和针对 MySQL 的中断运行?
  2. 您认为从集成测试到单元测试是“降级”之王吗?
  3. 您认为放弃集成测试并采用单元测试来考虑速度是否可行。
  4. 我知道存在一些针对内存数据库运行测试的框架(即 Effort 框架),但我看不出这与模拟相比有什么优势,我缺少什么?

我知道这类问题很容易出现“这取决于您的需求”类型的回答,但我相信有些人可能已经经历过这个问题并且可以分享他们的知识。我也知道,在一个完美的世界里,我会同时做这两个(使用模拟和使用数据库进行测试),但我没有这样的时间。

作为一个附带问题,您会推荐什么工具来模拟。有人告诉我“起订量”是一个很好的框架,但它有点慢。你怎么看?

【问题讨论】:

  • 单元测试用于测试编写的代码,集成测试用于测试与其他的事物的交互> 写道。您不应该消除集成测试,但它们不应该是您每 10 分钟运行一次的测试。
  • 通常,良好的关注点分离和依赖注入将允许您测试应用程序中的几乎每个函数,就好像它是整个应用程序本身一样。如果你的函数依赖于其他函数/服务/库的结果来给出正确的响应,那么它很可能重构得不够充分。

标签: entity-framework unit-testing asp.net-mvc-5 integration-testing


【解决方案1】:
  1. 您是否认为模拟我的数据库可以“隐藏”仅当我的代码针对真实数据库运行时才会出现的错误?请注意,我不想测试 Entity Framework(我相信微软的优秀人员在这方面做得很好),但是我的代码能否很好地针对模拟和针对 MySQL 的中断运行?

是的,如果您只使用 Mocks 测试您的代码,那么您很容易对您的代码产生错误的信心。当您模拟数据库时,您正在做的是说“我希望这些调用会发生”。如果您的代码进行了这些调用,它将通过测试,但如果它们是错误的调用,它将无法在生产中工作。简单来说,如果您从数据库中添加/删除列,则数据库交互可能需要更改,但是在您更新模拟之前,添加/删除列的过程对您的测试是隐藏的。

  1. 您认为从集成测试到单元测试是“降级”之王吗?

这不是降级,而是不同。单元测试和集成测试具有不同的优势,在大多数情况下可以相互补充。

  1. 您认为放弃集成测试并采用单元测试来考虑速度是否可行。

好的是非常主观的。我会说不,但是您不必每次都运行 all 的所有测试。大多数测试框架(如果不是全部)允许您以某种方式对测试进行分类。这允许您创建测试的子集,例如,您可以有一个“DatabaseIntegration”类别,您可以将所有数据库集成测试放入其中,或者“EndToEnd”用于完整的端到端测试。我首选的方法是单独构建。我在每次签入之前/之后运行的通常/连续构建仅运行单元测试。这提供了快速反馈和验证,没有任何问题。除了运行单元测试之外,不太常见的/每日/隔夜构建还会运行较慢/可重复的集成测试。如果代码有可能影响集成,我也会倾向于在签入代码之前对我一直在研究的领域进行集成测试。

  1. 我知道存在一些针对内存数据库运行测试的框架(即 Effort 框架),但我看不出这与模拟相比有什么优势,我缺少什么?

我没有使用它们,所以这是猜测。我想主要的好处是,您不必模拟与模拟的数据库交互,而是设置数据库并测量发布状态。测试变得更少如何您做了某事而更多移动了哪些数据。从表面上看,这可能会导致测试不那么脆弱,但是您正在有效地针对另一个您不会在生产中使用的数据提供者编写集成测试。如果这是正确的做法,那也是非常主观的。

我想第二个好处可能是您不一定需要重构代码来利用内存数据库。如果您的代码尚未构建为支持依赖注入,那么您很有可能需要执行某种程度的重构以支持模拟。

我也知道,在一个完美的世界中,我会同时做这两个(使用模拟和使用数据库进行测试),但我没有这样的时间。

我真的不明白你为什么会这样。您已经说过您已经计划用单元测试替换集成测试。除非您需要进行重大重构以支持单元测试,否则您的集成测试应该仍然有效。您通常不需要像需要单元测试那样多的集成测试,因为单元测试用于验证功能,集成测试用于验证集成,因此创建它们的开销应该相对较小。使用分类来确定您运行的测试将减少运行测试的时间影响。

作为一个附带问题,您会推荐什么工具来模拟。有人告诉我“起订量”是一个很好的框架,但它有点慢。你怎么看?

我使用了很多不同的模拟库,并且在大多数情况下,它们都非常相似。使用不同的框架,有些事情会更容易,但是如果不知道你在做什么,很难说你是否会注意到。如果您在构建代码时没有考虑到依赖注入,那么您可能会发现将您的模拟放到您需要它们的位置是一项挑战。

任何类型的模拟通常都非常快,您通常(除非您使用部分模拟)删除您正在模拟的类/接口的所有功能,因此它的执行速度将比您的正常代码更快。我听说的唯一性能问题是,如果您是 MS 伪造品/垫片,有时(取决于被伪造的程序集的复杂性)可能需要一段时间才能创建伪造的程序集。

我使用的两个略有不同的框架是 MS fakes/shims 和 Typemock。 MS 版本需要一定级别的 Visual Studio,但允许您使用特定类型对象的 shim 生成假程序集,这意味着您不必将模拟从测试传递到使用它们的地方。 Typemock 是一种商业解决方案,它使用分析 API 在您的测试运行时注入代码,这意味着它可以到达其他模拟框架无法到达的部分。如果您的代码库没有考虑到单元测试来帮助弥合差距,那么这些都特别有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-05-05
    • 2010-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-01
    相关资源
    最近更新 更多