几个月前,我开始进行测试自动化的实验。每个测试在开始之前都会获取随机的测试数据。例如,当我的测试要求具有管理特权的用户时,我随机抽取一个帐户,然后从该帐户的一组管理员用户中随机抽取一个管理员用户。

使用random的原因测试数据有两个方面:


首先,当我们使用静态(即硬编码的测试数据)时,有时测试开始失败,因为测试数据不再存在于DB中,例如,某个用户已从数据库中删除(我们的测试数据库中有生产转储,因此我猜该用户已在生产中删除)。当我们开始在运行时找到此类用户时,问题就消失了。
第二个问题是,不清楚为什么将某些测试数据用于特定测试。我们继承了其他团队的测试,因此无法理解其背后的意图,例如使用用户“ xyz@awesome.com”。通过编写查询以查找数据,我们开始明确声明所需的测试数据类型,例如,我们希望具有管理特权的用户。

虽然我的方法解决了这两个问题,但它也引入了一些方法新问题:


测试有时会失败,因为它们选择了错误的测试数据。这是因为查询有时不正确。例如,一旦测试抽取了一个完全没有管理员的随机帐户。这样做的好处是,通过这种方式,我可以不断学习有关被测系统的新知识,例如,必须有业务原因才能拥有没有管理员的帐户。
随着查询的增长,测试设置变得越来越复杂因此测试似乎现在变得更难理解。

我也希望通过使用随机测试数据来扩大覆盖范围并发现更多错误,就像在模糊测试中一样。相反,我主要在测试中发现错误,并了解到我对被测系统的了解很少。最后,投资回报率似乎并不高。更改之前,维护静态测试数据(如果过时则要更新测试数据)要付出代价。现在,当测试采用“错误的”测试数据时,我必须维护复杂的查询,并且这种情况比以前的静态测试数据更经常发生。

我想知道使用随机测试数据是否真的有意义和怎么做对呢?

#1 楼

好问题。我看到两个问题,如下所示。

使用随机数据可能会导致无法重复的结果。您可以通过记录(或记录)您做出的每个随机选择,然后回放这些选择来减轻这种情况。假设您的数据不会随着时间变化,这就像将初始种子记录到随机数生成器一样容易。

很难以足够通用的方式编写测试来处理任意,随机选择的数据。这是更困难的问题。选择一个不同的随机整数是一回事。选择其他用户(属性随一个用户变化到另一个用户)是另一回事。考虑一下测试在抽象中的工作方式:它选择一些输入,将它们应用于函数,然后验证结果是否正确。有几种方法可以实现:




开发人员预先计算预期结果并将其硬编码到测试中。这只有在开发人员提前决定输入的情况下才有效。

测试使用输入来计算预期结果,然后将其与实际结果进行比较。如果测试可以使用任意(随机输入),则意味着测试需要在被测系统中复制很多逻辑。这几乎肯定不是您想要的,尤其是对于复杂的系统。您和开发人员一样有可能以错误的方式实现复杂的算法。

测试使用其他方法来验证结果是否与输入匹配。有时您可以使用快捷方式,或者至少是替代方法来验证结果。举一个朴素的例子,如果系统对一个数字列表求和,则可以验证结果,但从和中减去该列表,然后检查新结果是否为零。大多数系统无法通过这种方式进行测试。

比较器测试是使用随机选择的数据的好地方,在该测试中,您使用相同的输入比较同一系统的两个版本。比较器测试不会告诉您系统是否正确,但可以帮助您发现行为的变化。您可能要考虑一下。

评论


回复:“如果测试可以使用任意(随机输入),则意味着测试需要在被测系统中复制很多逻辑。”好吧,我已经看到了吸引随机用户的解决方案,如果该用户的类型为A,则检查断言X,对于B则检查Y。这显然是重复逻辑。我正在做另一件事:定义用户类(使用SQL),然后绘制属于该类的随机用户。您在等效类分区中也执行相同的操作。那有什么区别呢?在这两种方法中,您都可以通过定义错误的类或选择错误的此类代表来失败。

– dzieciou
15年1月28日在21:04



并不是您是否重复逻辑;这是您需要复制的数量。如果您在具有复杂数据模型的应用程序中使用随机数据,最终可能会陷入困境。

–user246
15年1月28日在21:32

这是一篇描述“不要重复逻辑”想法的Google博客文章:googletesting.blogspot.se/2015/01/…

–user246
15年1月30日在16:19

#2 楼

但是,如果您获得测试数据,就想知道它适合于测试的目的。

在测试本身之外定义测试数据时,总是有机会使数据将偏离测试的意图。如果数据是由测试自动化员以外的其他人维护的,则机会增加。 。忽略重要标准是很常见的(在您学习中)。您的测试最终对查询未执行的任何条件做出了毫无根据的假设。或者您应用所有条件,但是随着测试数据的更改,查询最终可能找不到满意的项目。

一般的危险:进行自动化测试取决于他们无法控制的任何事情,这可能导致无论系统是否满足职责,测试都会失败。也就是说,您的测试最终会说谎,而人们很快就会停止信任它们。

有几种方法可以解决问题。

让测试控制测试数据。一种方法是给每个测试控件自己的测试数据。即:让每个测试创建其测试数据,而不是从其他位置维护的数据池中选择它。建立测试数据会使每个测试运行起来更加昂贵和耗时。但这使测试更加可靠。

伪造数据库。要解决昂贵的测试数据设置问题,您可以从测试中删除真实的数据库,然后使用伪造的数据库。最大的优点是:您可以控制数据,而无需建立真实数据库的开销。最大的缺点是:假数据库的行为可能与真实数据库不同,并且测试最终说谎。这是一个折衷,如果您可以创建具有足够保真度的假数据库,则会更加可口。

受控随机性。使用这两种方法中的任一种,如果要随机化数据,都可以直接进行处理,可以将所需的特定属性随机化,然后以所需的方式将其随机化。

评论


戴尔,在阅读您的评论后,我得出的结论是我尚未进行测试。我已经做了某种抽样来回答以下问题:(1)让我们看看哪些用户/帐户/组属于此类用户/帐户/组,以及(2)让我们看看哪些因素/维度描述了此问题类。例如,我发现要管理用户,您需要的不仅仅是管理特权。因此,这是学习新系统并获得测试设计投入的一种方式,而不是测试自己。

– dzieciou
15年1月30日在8:57

#3 楼

当然,随机测试比示例测试更有意义。不同的情况需要不同的解决方案:随机用户(或其他对象):需要在每次测试运行时都创建它们。或者他们通过一些查询选择它,但是这样做不那么健壮。

使用随机数据测试验证是最简单的-您可以使用现有库生成所需的值,然后检查验证是否通过。

测试算法/计算可能需要更复杂的方法-基于属性的测试。无需检查输出值,而是检查结果的属性。

当您可以调用系统的随机函数时,随机行为是另一种不错的技术。这可以通过基于模型的测试来实现。

您可以在本文中找到有关不同技术的更多信息。

另一个问题是如何简化利用随机化的测试:
/>

大多数时候,您可以负担得起为测试创建自己的域模型(或重用用于生产代码的类)。此类对象(例如User)在创建时可以默认填充所有必填字段。例如。如果用户需要用户名,密码,电子邮件,则您在创建用户时会随机生成它们(例如User.random())。如果在测试中特别检查用户名,则可以用测试所需的用户名覆盖它。这样,测试中仅会显示测试所需的数据。

请勿将数据从代码移至外部文件中-否则您将无法随机生成它们,否则将更加困难。

建立测试金字塔,以将大多数测试保持在单元,组件级别。如果您有成千上万的系统测试,那么碰撞的几率会越来越高,因为以前的记录是在以前的运行中遗留下来的。当您测试唯一字段的最小边界时(例如,它是1个符号),这可能是一个问题。低级测试没有此问题,因为它们没有存储空间或寿命短。

使用专用的库,例如Java的Datagen或JS的random-ext。