这正是我的项目中发生的事情,今天,我将告诉您如何在不损失质量的情况下进一步减少测试用例的数量。
测试对象
首先,我将简单介绍一下该产品。在Tinkoff,我们的团队开发了模块-这些是由实现和配置组成的React组件。实现是组件本身,我们已经开发了该组件,用户可以在浏览器中看到它。配置是JSON,用于设置此对象的参数和内容。
这些块的主要任务是要美观,并且对于不同的用户来说看起来是相同的。同时,该块的配置和内容可能会发生很大变化。
例如,一个块可以是这样的-没有背景,按钮和图片在右边:
或者像这样-有背景,按钮和图片在左边:
或者通常这样-用链接而不是按钮并且文本中没有列表:
上面的所有示例都是一个配置块的一个版本(一个特定的React组件可以处理的JSON结构),并且是同一块,但内容不同。
电路本身:
{
components: {
background: color,
panel: {
panelProps: {
color: {
style: ['outline', 'color', 'shadow', 'custom'],
background: color
},
size: ['s', 'm', 'l'],
imagePosition: ['left', 'right']
},
title: {
text: text,
size: ['s', 'l'],
htmlTag: ['div', 'b', 'strong', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']
},
description: {
text: html,
htmlTag: ['div', 'b', 'strong', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']
},
image: {
alt: text,
title: text,
image: {
src: image,
srcset: [{
src: image,
condition: ['2x', '3x']
}],
webpSrcset: [{
src: image,
condition: ['1x', '2x', '3x']
}]
},
imageAlign: ['top', 'center', 'bottom']
},
button: {
active: boolean,
text: text,
color: {
style: ['primary', 'secondary', 'outline', 'outlineDark', 'outlineLight', 'textLink', 'custom'],
backgroundColor: color
},
onClick: {
action: ['goToLink', 'goToBlock', 'showBlock', 'crossSale', 'callFormEvent'],
nofollow: boolean,
url: url,
targetBlank: boolean,
title: text,
noindex: boolean,
guid: guid,
guidList: [{
guid: guid
}],
formId: guid,
crossSaleUrl: url,
eventName: text
},
htmlTag: ['div', 'b', 'strong', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']
},
href: url
}
}
}
在这种情况下,右侧图片的块将具有一个值
components.panel.imagePosition = right
。并且左侧图片的区块具有components.panel.imagePosition = left
。对于带有按钮的块-components.button.active = true
依此类推。我希望这个原则是明确的。这就是设置块的所有参数的方式。
参数组合案例
在本文中,我不会涉及框图版本控制,内容填充规则或数据来源的问题。所有这些都是独立的主题,不会影响一组测试用例的编译。要知道的主要事情:我们有许多影响组件的参数,并且每个参数都可以采用自己的一组值。
对于上面的示例,我选择了一个配置非常简单的块。但是即使在这种情况下,检查所有参数的值的所有组合也将花费不可接受的长时间,尤其是在您必须考虑跨浏览器兼容性的情况下。通常,成对测试或成对测试在这里很重要。关于他的文章已经大量撰写,甚至进行了培训。如果您突然没碰到-请务必阅读。
让我们估计一下在应用它时将得到多少个测试用例。我们有25个以上的参数,其中一些参数最多可使用7和9个值的变体。是的,您可以忽略一些东西:例如,如果您正在检查布局,则GUID对您并不重要。但是,使用成对测试,您仍然可以获得80多个测试用例。正如我已经写过的,这不是最复杂的块,并且没有考虑跨浏览器的兼容性。现在我们有150多个块,并且它们的数量正在增长,所以如果我们想保持测试和发布新版本的速度,我们负担不起这么多的案例。
一个参数的案例
成对测试方法基于以下陈述:大多数缺陷是由不超过两个因素的相互作用引起的。也就是说,大多数bug要么在一个参数的值上体现出来,要么在两个参数的值组合上体现出来。我们决定忽略此语句的第二部分,并假设检查一个参数仍然可以找到大多数错误。
事实证明,为了进行测试,我们需要至少检查一次每个参数的每个值。但是同时,每个块都包含整个配置。然后,在每种新情况下,您可以检查尚未验证的值的最大值,以最大程度地减少案例数。
让我们使用一个简化的示例来分析构造案例的算法。让我们从方案中获取按钮组件,并为其编写测试用例:
button: {
active: boolean,
text: text,
color: {
style: ['primary', 'secondary', 'outline', 'custom'],
backgroundColor: color
}
为了简化示例,我将列表的长度减少为
button.color.style
。
步骤1.为每个字段组合内容选项
这里的一切就像成对测试一样:您需要了解每个字段可以取什么值。例如,
button.active
在我们的情况下,可能只有两个值:true
或false
。从理论上讲,可能会出现更多选择,例如,undefined
缺少密钥本身。
我认为在这里非常重要的一点是,非常清楚地定义系统的边界和功能,而不要检查不必要的事情。也就是说,如果在第三方系统中实现了检查强制性密钥或验证值的功能,则需要在第三方系统中检查此功能。而且,我们仅应将“正确”数据用作案例。
总的来说,在测试金字塔中使用了相同的原理。如果需要,可以向我们添加最关键的集成测试-例如,检查尚未到达的密钥的处理。但是这种测试应该最少。另一种方法是追求详尽的测试,众所周知,这是不可能的。
因此,我们确定了每个字段的内容选项,并制作了下表:
该表包括每个参数的每个等效类,但仅包含一次。
在我们的例子中,这些是值类,这些类是:
- text_s-短字符串;
- text_m-更长的字符串;
- no_color-无颜色;
- rnd_color是任何颜色。
第2步。用数据丰富表
由于每个块都具有完整的配置,因此我们需要向空白单元格中添加一些相关数据:
现在每一列都是一种情况。
同时,由于我们自己选择丢失的数据,因此可以基于优先级生成案例。例如,如果我们知道短按钮比中长文本在按钮中的使用频率更高,那么值得对其进行更多检查。
在上面的示例中,您还可以注意“已删除”的情况-尽管表中存在某些参数,但根本未对其进行检查的情况。在这种情况下,
button.color.style: secondary
将不检查外观,因为禁用按钮的样式无关紧要。
为了防止“掉落”的情况导致错误,我们通常使用分析所得的值集。在生成测试用例的过程中,分析执行一次,然后将所有“删除的”用例手动添加到最终测试用例中。这种解决方案相当笨拙,但价格便宜(当然,除非您很少更改测试对象的配置)。
一个更通用的解决方案是将所有值分为两组:
- 不安全的价值(那些可能导致案件“损失”的价值);
- 安全(不会导致“崩溃”)。
每个不安全值都在其自己的测试用例中进行检查,您可以使用任何安全数据丰富该用例。为了获得安全值,将根据上述说明编译表。
步骤3.澄清值
现在剩下的就是生成具体的值而不是等效类了。
在这里,每个项目都必须根据测试对象的特征选择自己的值变体。一些值很容易产生。例如,您可以为大多数字段简单地采用任何颜色。对于某些块,在检查颜色时,您必须添加一个渐变,但是将其移动到单独的等效类中。
对于文本,则稍微复杂一点:如果您是根据随机字符生成字符串,则不会测试连字符,列表,标签,不间断空格。我们从真实文本生成短和中等的行长,并将其修剪到所需的字符数。在长文本中,我们检查:
- html标记(任何一个);
- 链接;
- 未编号清单。
这组情况直接源于我们的块实现。例如,所有html标记都连接在一起,因此测试每个标记都没有意义。在这种情况下,将单独检查链接和列表,因为它们具有单独的视觉处理(突出显示悬停和点决)。
事实证明,对于每个项目,您都需要根据测试对象的实现来编写自己的实际内容集。
算法
当然,乍看之下,该算法似乎很复杂,不值得付出努力。但是,如果您忽略了我在上面每个段落中试图描述的所有细节和例外,结果将非常简单。
步骤1.将所有可能的值添加到参数表中:
步骤2.将值复制到空单元格中:
步骤3.将抽象值转换为具体值并获得
大小写:表的每一列都是一个大小写。
该方法的优点
这种生成测试用例的方法具有多个重要优点。
更少的案件
首先,比成对测试少得多。如果我们使用一个带有按钮的简化示例,则在成对测试中我们得到了4个案例,而不是8个案例。
被测对象中的参数越多,案例节省的意义就越大。例如,对于本文开头介绍的完整内容,在成对的帮助下,我们得到了11个案例-260。
案件数量并未因功能复杂性而膨胀
第二个优点是,当在测试过程中考虑到新参数时,案例数不会总是增加。
例如,假设一个参数
button.color.textColor
具有值等效类,no_color
并且已添加到我们的button中rnd_color
。然后剩下4个案例,每个
案例仅添加一个参数:案例数量只会在某些参数具有比案例更多的值的情况下才会增加。
您可以更经常地检查重要
通过丰富值(算法中的步骤2),可以更频繁地检查较高优先级或较高风险的值。
例如,如果我们知道早期用户经常使用较短的文本,而现在他们使用较长的文本,则可以用较长的文本来丰富案例,并更多地进入真实的用户案例。
可以自动化
上面的算法非常适合自动化。当然,该算法生成的案例看起来要比人工生成的案例少一些,而不是真实的案例。至少通过匹配颜色和裁剪文本。
但是,另一方面,在开发过程中却没有测试人员的参与,就会出现案例,从而大大减少了反馈循环。
缺点
自然,这种案例的产生远非万灵丹,而且也有其缺点。
难以分析结果
我认为您已经注意到,在生成案例的过程中,测试数据相互混合。因此,当箱子跌倒时,确定跌倒原因变得更加困难。毕竟,在此情况下使用的某些参数不会以任何方式影响测试结果。
一方面,这确实使解析测试结果变得困难。但是,另一方面,如果被测对象需要大量必需的参数,则这也很难找到导致错误的原因。
可能会遗漏错误
回到本文的开头:使用此方法时,我们可以跳过由两个或多个参数组合引起的错误。但是我们会以速度取胜,因此,由您来决定对每个特定项目来说更重要的是什么。
为了避免两次遗漏错误,我们引入了“零错误政策”,并开始使用附加的测试用例关闭每个遗漏的错误-不再自动生成,而是用手工编写。这产生了出色的结果:我们现在有150多个块(已测试的对象),每天有多个版本,每月有0到3个非关键错误丢失。
结论
如果您的被测对象具有广泛的输入参数,并且您想尝试减少案例数,从而减少测试时间,则建议您尝试使用上述使用一个参数生成案例的方法。
在我看来,它是前端组件的理想选择:您可以将时间减少三倍以上,例如,通过屏幕截图测试来检查外观。由于案件最早出现,因此发展将会更快。
当然,如果您正在测试新特斯拉的自动驾驶仪,那么即使丢失错误的可能性很小,也不应忽略。但是在大多数情况下,请不要忘记现代世界中的速度是非常重要的质量标准。与发现的几个小问题相比,速度的提高给出了更为积极的结果。
对于最负责任的人,在下一篇文章中,我将告诉您如何使用自定义案例和StoryBook来保护自己免受参数组合所引起的棘手错误。