提升测试效率:语义化HTML如何改变端到端测试

语义化和可访问的HTML不仅是增强人类交互的强大工具,而且还提高了软件系统的效率。例如,当用户填写具有清晰标签和可访问输入字段的表单时,这减少了错误,并确保向后端和数据库发送准确的数据。良好结构化的网页对搜索引擎优化(SEO)至关重要。
为每个开发者的首要关注点应该是创建对每个人都易于访问和使用的工艺品。好消息是,优先考虑这个方面也可能产生积极的效益:它使您的网站与其他软件组件之间的交互变得无缝

语义化HTML、可访问性和测试之间的关联

这个主题由Rita Castro在她的演讲《a11y和TDD:完美匹配》中进行了精彩探讨。尽管Rita主要关注单元测试,但值得一提的是,这些原则也可以应用于端到端测试,并且出于同样的原因。

端到端测试困境

端到端测试超越了对网站各个部分的检查。它试图像真实用户在真实的Web浏览器中那样操作,测试整个网页,就像真正使用它的人所看到的那样。

让我们想象我们正在为一个列表项组件编写一个单元测试,该组件生成以下HTML

1
2
3
4
<li>
一个项目的描述
<button type="button">选择此项</button>
</li>

而单元测试可以像这样针对按钮:

1
screen.getByRole('button')

这种方法非常适合于在孤立环境中测试组件,这就是所谓的“单元”意味着的。它简化了测试,因为不用担心页面上其他可能存在的按钮,也不用考虑上下文。

然而,单元测试无法完全复制真实场景。例如,它们无法确保点击按钮会为当前用户保存一些数据并导航到另一页。

现在,考虑一下我们的列表项在一个完整的网页中使用,其中包含一个包含按钮和列表容器之外的其他部分的顶部栏。页面中的列表没有以语义化和可访问性为目标构建,因此它看起来像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<body>
<div id="root">
<div>
<div>
<div>
<div>
<div>
<!-- topbar -->
</div>
<div>
<div>
<header>
<div>
<h1>Page Title</h1>
<h3>Page subtitle</h3>
</div>
</header>
<div>
<!-- a form for filtering the list -->
<hr />
<div>
<div>
<div>
<div>
<div>
<p>A description for this item</p>
</div>
</div>
</div>
<div>
<button>
<span> Pick this item </span>
</button>
</div>
</div>
<div>
<div>
<!-- second item -->
</div>
<!-- ... -->
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>

大多数端到端测试工具都可以在您与网页交互时记录您的操作,然后将这些操作用于自动化。它们保存选择器以自动识别您与之交互的项目。
我们希望测试列表中第一个元素中按钮的点击。我必须承认,我在示例中简化了HTML,工具生成的实际选择器看起来像这样:

1
//*[@id="root"]/div/div/div/div/div/div/div[3]/div/div/div[2]/div[1]/div[2]/button

每当您调整HTML,即使仅添加或删除一个div包装器,您的测试套件也很容易在这种情况下混乱。端到端测试不是每天更新的东西,因为它们速度慢,需要大量资源。因此,弄清楚为什么测试失败可能是耗时的,并且会让您从更重要的任务中分心。

测试工具在识别目标方面越来越好,但是算法并不是百分之百可靠的,不能以100%的可靠性对页面结构更改做出反应。这就是为什么重要的是目标可以无歧义地被识别。获得这种清晰度的常见技术之一是向HTML元素添加唯一的ID、测试ID或其他选择器,但这不是最佳实践,有几个原因:

  • 关注分离:将测试关注点与应用程序的业务逻辑混合在一起违反了关注分离原则。您正在耦合两个不同且独立的对象,而且一个在其中一侧工作的人可能完全不知道另一侧正在使用和必要的东西。这个人也可能是在某些时间内没有在一侧工作过的同一个人,并在此期间失去了上下文。
  • 可维护性:随着应用程序的增长和变化,测试ID可能需要更改或发展。当您直接将这些ID嵌入到代码中时,当测试要求发生变化时,您可能需要在整个代码库中进行广泛的更改。这可能是耗时且容易出错的。
  • 代码混乱:在源代码中嵌入与测试相关的标识符可能会使代码库变得混乱,并使开发人员难以阅读。
  • 可访问性:添加测试ID积极地错过了免费的可访问性测试机会。如果我的测试套件明确寻找按钮,它也确保目标仍然是一个可访问的按钮,并且不会被重构为不语义化的div。

    测试中语义化HTML的能力

    现在,设想一个不同的场景,您的列表是使用干净、语义化的HTML构建的。我们不使用自动定位算法,而是为列表中的第一个项目添加手动选择器,如下所示:
1
//*li[1]/button

无论您对列表项周围结构进行了任何HTML更改,您的测试都保持非常稳定。总结一下:

  • 依赖自动定位算法可能导致不稳定性,在最好的情况下,您需要重新生成目标。如果您的测试在更改标记的基本结构时需要进行调整,它们可能无法真实模拟用户的旅程,而是与实现细节过于紧密地相关。

  • 使用任意ID或其他唯一选择器是一种不规范的用法。

  • 拥有语义化的HTML使得易于进行手动定位,更能抵御变化。它还应该有助于检测可能破坏UI可访问性的操作。

    为什么重要

    那么,为什么您应该关心测试中的语义化HTML和可访问性呢?

  • 开发人员和QA工程师的福音:对于开发人员和QA工程师来说,生活变得更加轻松。当您可以使用简单、语义化的代码进行工作时,编写测试就变得轻而易举。

  • 模仿真实用户:您的测试更好地模仿了真实用户的行为。真实用户不会在您的Web应用程序中寻找div和span;他们会寻找具有清晰标签的标题、按钮、链接和熟悉的界面元素。

  • 可靠性和节省时间:您的测试变得更加可靠,并且不会因为任意原因在每次部署时都失败。告别无数小时调整测试的时光,迎接更加高效的工作。

总而言之,在开发过程中采用语义化的HTML和可访问性不仅仅是遵循最佳实践;它对于测试是一个改变游戏规则的因素。它简化了您的测试工作,使您的测试更加真实,并确保它们经得起时间的考验——为您节省宝贵的时间和挫折。因此,不要低估规范代码的力量;它可能是您测试中的隐形超级英雄。