业务导向且支持开发过程的测试
这一象限的测试通常称作功能测试或验收测试。验收测试确保用户故事的验收条件得到满足。在开发一个用户故事之前,就应该写好验收测试,采取完美的自动化形式。像验收条件一样,验收测试可以测试系统特性的方方面面,包括其功能(functionality)、容量(capability)、易用性(usability)、安全性(security)、可变性(modifiability)和可用性(availability)等。关注于功能正确性的验收测试称作功能验收测试,而非功能验收测试归于图中的第四象限。如果对于功能与非功能测试有模糊认识且常常搞不清他们的区别,
在敏捷环境中,验收测试是致关重要的,因为他们可以回答如下一些问题。对开发人员来说,它回答了“我怎么知道我做完了呢?”对用户来说,它回答了“我得到我想要的功能了吗?”当验收测试通过以后,它所覆盖到的需求或用户故事都可被认为是完成了。因此,在理想情况下,客户或用户会写验收测试,因为他们定义了每一个需求的满足条件。时新的自动化功能测试工具,比如 Cucumber、JBehave、Concordion 以及 Twist,都旨在把测试脚本与实现分离,以达到这种理想状态,并提供某种机制方便地将二者进行同步。在这种方式下,由用户来写测试脚本是可能的,而开发人员和测试人员则要致力于实现这些测试脚本。
总之,对于每个需求或用户故事来说,根据用户执行的动作,一定会找到应用程序中一个中规中矩的执行路径,这称为 Happy Path。Happy Path 通常如下方式来描述:“假如[当测试开始时,系统所处状态的一些重要特征],当[用户执行某些动作后],那么[系统新的状态的一些重要特征]。”有时这称为测试的“given-when-then”书写模型。
然而,除最简单的系统外,任何用例的初始状态、被执行的动作以及执行后的结果状态都会有所不同。有时候,这些变化会形成不同的用例,也就是无所谓的 Alternate Path。另外,这些变化还可以引发一些错误处理。从而导致无所谓的 Sad Path。很明显,还有很多测试,因为对于其中的可变因素,给予不同的值会得到不同的结果。等价划分分析(equivalence partitioning analysis)和边界值分析可以帮助你得到尽可能小的用例集合,并保证测试覆盖完整的需求。然而,即便如此,你也要凭直觉来挑选一些最为相关的用例。
系统的验收测试应该运行在类生产环境中。例如手工验收测试,它通常是将应用部署在用户验收测试(UAT)环境后进行的。这个环境应该尽可能与生产环境相似(无论是配置还是应用程序的状态)。不过对于那些外部服务来说,我们可能会使用一些模拟(mock)技术。测试人员通过应用程序的标准用户界面来执行测试工作。自动化验收测试也应该运行在类生产环境之上,并且测试用具(test harness)与应用交互的方式应该和真正的用户使用使用应用的方式相同。
自动化测试验收
自动化验收测试有很多很有价值的特性。
它加快了反馈速度,因为开发人员可以通过运行自动化测试,来确认是否完成了一个特定需求,而不用去问测试人员。
它减少了测试人员的工作负荷。
它让测试人员集中精力做探索性测试和高价值的活动,而不是被无聊的重复性工作所累。
这些验收测试也是一组回归测试套件。当开发大型应用或者在大规模团队中工作时,由于采用了框架或许多模块,对应用某一部分的更改很可能会影响其余特性,所以这一点尤其重要。
就像行为驱动开发(BDD)所建议的那样,使用人类可读的测试以及测试套件名,我们就可以从这些测试中自动生成需求说明文档。像 Cucumber 和 Twist 这样的工具,就是为了让分析人员可以把需求写成可执行的测试脚本而设计的。这种方法的好处在于通过验收测试生成的需求文档从来不会过时,因为每次构建都会自动生成它。
回归测试也是一个特别重要的话题。在前面的象限图中并没有回归测试,因为它是跨象限的。回归测试是自动化测试的全集。它们用来确保任何修改都不会破坏现有的功能,还会让代码重构变得容易些,因为可以通过回归测试来证明重构没有改变系统的任何行为。在写自动化验收测试时,应该时刻牢记,这些测试是回归测试套件的组成部分。
然而,自动化验收测试的维护成本可能很高。如果写得不好,它们会使交付团队付出极大的维护成本。由于这个原因,有些人不建议创建大而复杂的自动化测试集合,比如 James Shore[dayXYv]就持这种观点。然而,通过使用正确的工具,并遵循好的实践原则,完全可以大大降低创建并维护自动化验收测试的成本,从而令收益大于付出。
同样需要记住的是,并不是所有的东西都需要自动化。对于某些方面的测试来说,用手工方法做更好。易用性测试及界面一致性等方面很难通过自动化测试来验证。尽管有时候测试人员会将自动操作作为探索性测试的一部分,比如初始化环境、准备测试数据等,但探索性测试不可能被完全自动化。很多情况下,手工测试就足够了,甚至优于自动化测试。总之,我们倾向于将自动化验收测试限于完全覆盖 Happy Path 的行为,并仅覆盖其他一些极其重要的部分。这是一种安全且高效的策略,但前提条件是其他类型的自动化回归测试是很全面的。一般我们将代码覆盖率高于 80%的测试视为“全面的”测试,但测试质量也非常重要,单单使用覆盖率这一指标是不够的。我们这里所说的测试覆盖率包括单元测试、组件测试和验收测试,每一种测试都应该覆盖应用程序的 80%(我们并不认同 60%的单元测试覆盖率加上 20%的验收测试覆盖率就等于 80%的覆盖率这一天真的想法)。
作为对自动化验收测试覆盖率比较好的一种评估方法,可以考虑下面的情形:假设要替换系统中的某一部分(比如持久层,使用另一种实现来替换它)。当你完成替换时,运行了自动化测试,并且测试全部通过了。你有多大自信心,认为系统可以正常运行呢?一个好的自动化测试套件应该给你足够的信心执行重构,甚至对应用程序架构进行重构。而且,假如测试能全通过,就证明应用程序的行为没有受到影响。
对于软件开发的各个方面,各个项目之间都会有所不同,你需要监控到底花了多长时间做重复性的手工测试,以便于决定什么时候把它们自动化。一个很好的经验法则就是,一旦对同一个测试重复做过多次手工操作,并且你确信不会花太多时间来维护这个测试时,就要把它自动化。更多关于何时做自动化的内容,
需要写的最重要的自动化测试是那些对 Happy Path 的测试。每个需求或用户故事都应该有对 Happy Path 的自动化验收测试,而且应至少有一个。这些测试应该被每位开发人员当做冒烟测试来使用,从而能够为“是否破坏了已有的功能”提供快速反馈。也就是说,这类测试应该是自动化的第一目标。
当你有时间写更多的自动化测试时,很难在 Happy Path 和 Sad Path 之间进行选择。如果你的应用程序比较稳定,那么 Alternate Path 应该是你的首选,因为它们是用户所定义的场景。如果你的应用有较多的缺陷并且经常崩溃的话,那么战略性地应用对 Sad Path 的测试会帮助你识别那些问题域并修复它们,而且自动化可以保证应用程序保持在稳定状态。
搜索微信公众号:TestingStudio 霍格沃兹的干货都很硬核
评论