不鼓励订单中的单元测试吗?

时间:2014-10-07 18:06:22

标签: unit-testing tdd

我有一个需要为其编写测试的大型程序。我想知道编写以特定顺序运行的测试是否错误,因为某些必须按顺序运行并且依赖于之前的测试。

例如以下场景:

  • CreateEmployer
    • CreateEmployee(需要雇主)
    • 添加部门

我看到这种方法的缺点是,如果一个测试失败,所有以下测试也将失败。但是,我将不得不编写代码来构建数据库,因此使用构建模拟数据库的代码作为一种类似集成的单元测试可能是一种更有效的方法。

我是否应该在不使用测试作为种子方法的情况下创建数据库,然后再次运行每个方法以查看结果?我用这种方法看到的问题是,如果种子方法不起作用,则所有测试都将失败,并且不会立即清楚错误是在种子方法中而不是服务或测试本身。

4 个答案:

答案 0 :(得分:2)

是的,不鼓励这样做。测试不应该在时间上耦合"。

每个测试都应该完全隔离其他测试。如果您发现自己处于测试B需要测试A创建的工件的情况下,那么您有两个问题需要纠正:

  • 测试A不应该创建工件(或副作用)。
  • 测试B应该使用模拟数据作为其安排"安排"步骤。

基本上,单元测试不应该使用真正的数据库。他们应该测试代码的逻辑,而不是与基础结构依赖关系的交互。模拟这些依赖项以便仅测试代码。

答案 1 :(得分:2)

让单元测试相互依赖是一个坏主意。在您的示例中,您可能在CreateEmployer和AddDepartment中都存在缺陷,但是当由于CreateEmployer测试而导致所有三个都失败时,您可能会错误地认为只有CreateEmployer测试是真的'失败。这意味着您已经丢失了AddDepartment失败的有效信息。

另一个问题是,您可能在将来创建一个单独的工作流程,调用AddDepartment而不调用CreateEmployer。现在你的测试假设CreateEmployer将永远被调用,但实际上它并不是。所有三个测试都可以通过,但是应用程序仍然可能会中断,因为您有一个您不知道存在的依赖项。

最好的测试根本不依赖于数据库,而是允许您手动指定或者" Mock"数据。然后,您不必担心会破坏所有测试的无关数据库问题。

答案 2 :(得分:1)

如果这些是真正的单元测试,那么是的,由于几个原因,需要特定订单是一种不好的做法。

  1. 耦合 - 正如您所指出的,如果一个测试失败,那么后续测试也会失败。这将掩盖真正的问题。
  2. TDD - TDD的核心原则是使测试易于运行。如果这样做,开发人员更有可能运行它们。如果它们很难运行(例如我必须运行整个套件),那么它们就不太可能被运行并且它们的价值会丢失。

答案 3 :(得分:1)

理想情况下,单元测试不应该依赖于另一个测试的完成才能运行。在给定的序列中运行它们也很困难,但这可能取决于您的单元测试工具。

在您的示例中,我将创建一个测试CreateEmployer方法的测试,并确保它以您期望的方式返回一个新对象。

我要创建的第二个测试是CreateEmployee,如果该测试需要使用依赖注入的Employer对象,则CreateEmployee方法可以接收其Employer对象。在这里,您将使用模拟对象(一个代码来创建,返回一个固定/已知的雇主)作为CreateEmployee方法将使用的Employer对象。这使您可以使用Employer对象的给定/已知实例测试CreateEmployee方法及其对该对象的操作。

你的第三个测试,AddDepartment,我假设还取决于雇主对象。此单元测试可以遵循相同的模式,并在测试期间向消费者接收模拟的Employer对象。 (你传递给上面两个单元测试的同一个对象。)

现在每个测试都自行运行/失败,并且可以按任何顺序运行。

相关问题