MVC 5 单元测试与集成测试

MVC 5 Unit tests vs integration tests

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

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

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

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

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

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

  1. Do you think mocking my database can “hide” bugs that can occur only when my code is running against a real database? Note that I don’t want to test Entity Framework (I’m sure the fine people from Microsoft did a great job on that), but can my code runs well against mocks and breaks against MySQL ?

是的,如果您只使用 Mocks 测试您的代码,您很容易对您的代码产生错误的信心。当您模拟数据库时,您所做的就是说 "I expect these calls to take place"。如果您的代码进行了这些调用,它将通过测试,但如果它们是错误的调用,它将无法在生产环境中运行。在简单的层面上,如果您从数据库中添加/删除列,数据库交互可能需要更改,但是 adding/removing 在您更新模拟之前,该列的过程对您的测试是隐藏的。

  1. Do you think going from integration testing to unit testing is a king of “downgrade”?

不是降级,是不一样。单元测试和集成测试有不同的好处,在大多数情况下会相互补充。

  1. Do you think dropping Integration testing and adopting unit testing for speed consideration is ok.

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

  1. I’m aware that some framework exists that run the tests against an in-memory database (i.e. Effort framework), but I don’t see the advantages of this vs mocking, what am I missing?

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

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

I’m also aware that in a perfect world I would do both (tests by using mocks and by using database) but i don’t have this kind of time.

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

As a side question what tool would you recommend for mocking. I was told that “moq” is a good framework but it’s a little bit slow. What do you think?

我使用过很多不同的模拟库,而且在大多数情况下,它们都非常相似。使用不同的框架,有些事情会更容易,但如果不知道自己在做什么,就很难说您是否会注意到。如果您在构建代码时没有考虑到依赖注入,那么您可能会发现很难将模拟应用到您需要的地方。

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

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