为什么 Mocha 测试用例应该是无状态的?

Why should Mocha test cases be stateless?

这是一个普遍的建议,Mocha 测试用例不应共享状态。鉴于 Mochas 执行测试用例的强烈顺序性,我真的不理解这个建议。还有更多 - 我觉得很可疑。

如果测试用例,即使是异步测试用例,严格地一个接一个地执行,就不会有时间竞赛问题或其他不可预测的执行顺序的风险。

让我们采用这个 Mocha 结构:

describe
   describe
     it1
     it2    // async
     it3
   describe
     it4
     it5
describe
   describe
     it6    // async
     it7    // async
     it8
   describe
     it9
     it10

测试用例将始终以清晰的顺序执行,it1、it2、...it10,独立于它们是同步还是异步,甚至独立于描述的层次结构。以下结构将产生完全相同的输出:

describe
   it1
   it2    // async
   it3
   it4
   it5
   it6    // async
   it7    // async
   it8
   it9
   it10

单个 describe() 中测试用例之间的共享数据可以使测试用例之间的通信变得更加容易和舒适,以便:

支持在测试用例之间使用共享数据的另一个事实是 Mocha 代码的这种简单而漂亮的结构。不同级别的 describe() 允许对最终共享数据进行简单明了的范围管理。

我看到的唯一不利方面是让代码更难理解、遵循和维护,而 "globals" 正在 "abused"。无论如何,没有什么是通过严格的编码无法避免的。

这里有什么我不知道的吗?

可能使用 Mocha 来 运行 测试非无状态的测试,因此相互依赖。这不是 Mocha 设计 的目的。归根结底,如果您想在测试之间施加依赖性,当然可以。不过它有一些注意事项。

针对错误的事情进行优化

您引用了在测试之间共享状态的优势:

to reduce the testing execution time

当然可以。 在其他条件相同的情况下, 我们宁愿有一个花费更少时间的测试套件 运行。在运行整个套件时,在大型测试套件上不重置测试之间的状态可能会节省相当多的时间。然而,事实是"all else"不等于:

  • 运行 整个套件应该由报告通过和失败的自动化流程完成。换句话说,应该没有人坐在那里等待整个套件完成。

  • 当出现故障或正在实施新测试时,开发人员将只想 运行 失败的测试或新测试,而不是整个套件。如果套件的设计使得测试 1 到 N-1 必须在测试 N 为 运行 之前为 运行,那么这就是开发人员等待获得实际测试结果的更多时间关心。这样他就可以坐在那里以 $X/minute 的速度摆弄他的拇指。 "Multitask" 不是答案,因为已经证明切换任务会产生认知成本。 ("Ok the test is done... wait, what was the issue again?")

测试选择

您可以使用 --grep 到 select 特定测试。这在大型测试套件上 非常有用 以避免将时间浪费在您不关心的 运行 测试上。因此,让我们假设您的测试标题是 it1,... it10 并且您使用 --grep it7。由于 Mocha 将所有测试相互独立,因此它只会 运行 任何 beforebeforeEach 挂钩适用于 it7 和 运行 测试(然后 运行 任何 afterafterEach 挂钩适用于它)。在运行宁it7之前不会运行it1it6。为了 运行 这些测试,你必须设计一个 --grep 来涵盖所有必要的测试,这当然总是 可能 做但并不愉快.

在 运行 在浏览器中使用 Mocha 时得到的 HTML 界面中,如果您希望 Mocha 仅 运行 该测试,则可以单击该测试。同样,如果您想要修复单个失败的测试,这将非常有用。如果碰巧失败的测试依赖于一堆应该在它之前 运行 的测试,那么这个简单的点击根本就没有等价物。

测试订单

一般来说,如果您的测试必须 运行 按特定顺序进行,则必须小心确保拆分为多个文件的测试按测试所需的顺序加载 运行.

例如,可能使用全局结构在存储在不同文件中的测试之间共享状态。但是,当测试在不同的文件中时(其中一个文件 而不是 require 另一个),Mocha 处理文件的顺序完全取决于文件中的顺序当读取包含文件的目录时,文件系统会列出这些文件。对于那些想要基于词典排序的可预测顺序的人来说,有一个 --sort 选项。如果您想强加自己的任意顺序,那么我想您必须将文件命名为 01foo.js02bar.js

无论是在浏览器中使用 Node.js 到 运行 Mocha 还是 运行ning Mocha,都是如此。我有测试文件加载 RequireJS 的套件。请求模块 A、B、C 不能保证它们将按 A、B、C 的顺序加载,除非声明 C 依赖于 B(可能还有 A)并且 B 依赖于 A。