测试

如果语言不会帮助我们发现错误,我们将不得不努力找到它们:通过运行程序并查看它是否正确执行。

一次又一次地手动操作,是一个非常糟糕的主意。 这不仅令人讨厌,而且也往往是无效的,因为每次改变时都需要花费太多时间来详尽地测试所有内容。

计算机擅长重复性任务,测试是理想的重复性任务。 自动化测试是编写测试另一个程序的程序的过程。 编写测试比手工测试有更多的工作,但是一旦你完成了它,你就会获得一种超能力:它只需要几秒钟就可以验证,你的程序在你编写为其测试的所有情况下都能正常运行。 当你破坏某些东西时,你会立即注意到,而不是在稍后的时间里随机地碰到它。

测试通常采用小标签程序的形式来验证代码的某些方面。 例如,一组(标准的,可能已经由其他人测试过)toUpperCase方法的测试可能如下:

  1. function test(label, body) {
  2. if (!body()) console.log(`Failed: ${label}`);
  3. }
  4. test("convert Latin text to uppercase", () => {
  5. return "hello".toUpperCase() == "HELLO";
  6. });
  7. test("convert Greek text to uppercase", () => {
  8. return "Χαίρετε".toUpperCase() == "ΧΑΊΡΕΤΕ";
  9. });
  10. test("don't convert case-less characters", () => {
  11. return "مرحبا".toUpperCase() == "مرحبا";
  12. });

像这样写测试往往会产生很多重复,笨拙的代码。 幸运的是,有些软件通过提供适合于表达测试的语言(以函数和方法的形式),并在测试失败时输出丰富的信息来帮助你构建和运行测试集合(测试套件,test suite)。 这些通常被称为测试运行器(test runner)。

一些代码比其他代码更容易测试。 通常,代码与外部交互的对象越多,建立用于测试它的上下文就越困难。 上一章中显示的编程风格,使用自包含的持久值而不是更改对象,通常很容易测试。