测试用例优化——基于相似性最小化测试数量

Test Case Optimization - minimizing # of tests based on similarity

我有几个测试用例,我想通过使用 Jaccard 矩阵的基于相似性的测试用例选择方法来优化。第一步是选择相似度指数最高的一对,然后保留一个作为候选,删除另一个。

我的问题是:根据什么策略,你选择去掉两个最相似的测试用例中的哪一个?尺寸?测试覆盖率?或者是其他东西?例如这里 TC1TC10 具有最高的相似度。你会移除哪一个?为什么?

这取决于你为什么这样做,静态代码指标只能给你建议。


如果您想让测试更易于维护,请查找重复的测试代码并将其extract 放入共享代码中。两个重要的例子是测试设置和期望。

例如,如果您倾向于一遍又一遍地进行相同的设置,则可以将其提取到 fixtures or test factories. You can share the setup using something like setup/teardown methods and shared contexts

如果您发现自己一遍又一遍地执行相同类型的代码来测试条件,请将其提取到共享示例中,例如测试方法或 matcher or a shared example。如果可能,用现有库中的断言替换自定义测试代码。


另一个指标是找到测试太多的测试。如果单元 A 调用单元 B 和 C,则测试可能会为 B 和 C 进行设置和测试。这可能是很多额外的工作,使测试更加复杂,并使单元相互依赖。

由于所有单位 A 关心的是他们对 B 和 C 的特定调用是否有效,请考虑将对 B 和 C 的调用替换为 mocks。这可以极大地简化测试设置和测试性能,并缩小您测试的范围。

但是,要小心。如果 B 或 C 发生变化,A 可能会中断,但 A 的单元测试不会捕捉到这一点。您需要一起为 A、B 和 C 添加集成测试。幸运的是,这个集成测试可以非常简单。它可以相信 A、B 和 C 单独工作,它们已经过单元测试,它只需要测试它们一起工作。


如果您这样做是为了加快测试速度,请先 profile 测试以确定它们为何缓慢。

考虑并行化是否有帮助。考虑代码本身是否太慢。考虑一下代码是否过于相互依赖并且必须做太多工作才能测试一件事。考虑一下您是否真的必须将所有内容写入磁盘或数据库等慢速资源,或者如果有时在内存中执行也可以。

因为它们具有相似的代码而认为测试是多余的,这是具有欺骗性的。类似的测试可能会测试非常非常不同的代码分支。例如,将 1 与 1.1 传递给同一个函数这样简单的事情可能会调用完全不同的 类,一个用于整数,一个用于浮点数。

相反,通过在测试覆盖中寻找相似性来找到冗余。没有神奇的相似度百分比可以确定测试是否多余,您必须自己确定。

这是因为一行代码被覆盖并不意味着它已经过测试。例如...

def test_method
  call_a
  assert(call_b, 42)
end

这里call_a覆盖,但未测试。测试覆盖率只告诉你什么没有被测试,它不能告诉你什么已经被测试。

最后,测试覆盖冗余很好。单元测试、集成测试、验收测试和回归测试都可以覆盖相同的代码,但从不同的角度来看。


所有静态分析都可以为您提供冗余的候选对象。仅当它们确实是多余的并且只有目的时才删除多余的测试。简单重叠的测试可能会作为 regression tests。很多时候我在单元测试通过时得救了,但一些偶然的集成测试却失败了。重叠就好了。