手动探索性测试 – 发现意外问题

在这一部分,我们将认识到手动探索性测试在使用 TDD 时作为防御缺陷的重要防线的作用。

我们在 TDD 中面临的最大威胁在于我们能否全面考虑软件需要处理的所有条件。任何合理复杂的软件都有大量的输入组合、边缘情况和配置选项。

考虑使用 TDD 编写代码来限制销售给 18 岁及以上的买家。我们必须首先编写一个 “快乐路径” 测试来检查是否允许销售,使其通过,然后编写一个负面测试,确认可以根据年龄阻止销售。这个测试的形式如下:

public class RestrictedSalesTest {
    @Test
    void saleRestrictedTo17yearOld() {
        // ... 测试代码省略
    }

    @Test
    void salePermittedTo19yearOld() {
        // ... 测试代码省略
    }
}

当我们寻找错误时,错误是显而易见的:17 岁和 18 岁之间的边界会发生什么?18 岁的人可以购买这个产品吗?我们不知道,因为没有针对这个情况的测试。我们测试了 17 岁和 19 岁的情况。那么,在这个边界上应该发生什么?一般来说,这是利益相关者的决定。

自动化测试无法做到两件事:

  • 询问利益相关者他们希望软件做什么

  • 发现缺失的测试

这就是手动探索性测试的用武之地。这是一种充分利用人类创造力的测试方法。它利用我们的直觉和智慧来找出我们可能遗漏的测试。然后,它使用科学实验来发现我们对缺失测试的预测是否正确。如果证明是正确的,我们可以提供反馈并修复缺陷。这可以通过非正式讨论或使用正式的缺陷跟踪工具来完成。在适当的时候,我们可以编写新的自动化测试来捕获我们的发现,并为未来提供回归测试。

这种探索性测试是一项高度技术性的工作,基于对软件系统中存在的边界类型的了解。它还需要对本地部署和软件系统设置的广泛了解,以及对软件构建方式和缺陷可能出现位置的了解。在某种程度上,它依赖于了解开发者的思维方式,并预测他们可能忽略的事情。

自动化测试和探索性测试之间的一些关键区别可以总结如下:

Table 1. Table 11.1 – Automated versus manual exploratory testing
自动测试 手动探索性测试

可重复的

创造性的

测试已知结果

寻找未知结果

机器可以完成

需要人类的创造力

行为验证

行为调查

计划性

偶发性

测试由代码控制

测试由人类大脑控制

手动探索性测试将始终是必要的。即使是最好的开发者也会因为时间紧迫、分心或另一个本应是电子邮件的会议而受到影响。一旦注意力分散,错误很容易悄悄潜入。一些缺失的测试与边缘情况有关,这些情况我们无法单独看到。另一个人的视角通常会带来我们无法独自获得的新的见解。手动探索性测试为防御未被注意的缺陷提供了重要的额外层次。

一旦探索性测试发现了一些意外行为,我们可以将其反馈到开发中。在这一点上,我们可以使用 TDD 为正确行为编写测试,确认缺陷的存在,然后开发修复程序。我们现在有了修复程序和回归测试,以确保错误得到修复。我们可以将手动探索性测试视为我们遗漏的缺陷的最快反馈循环。探索性测试的优秀指南列在进一步阅读部分。

从这个角度来看,自动化测试和 TDD 并没有使手动工作变得不那么重要。相反,它们的价值被放大了。这两种方法共同作用,将质量构建到代码库中。

手动测试我们遗漏的内容并不是唯一无法自动化的有价值的开发时间活动。我们还有检查源代码质量的任务,这将是下一部分的主题。