变异分析,或如何测试

从来没有太多的测试-每个人都知道。 关于单元和集成测试的模因不再有趣。 但是我们仍然不知道是否有可能依靠通过测试的结果,以及覆盖率的百分比将使我们不让错误进入生产环境。 如果代码中的致命更改跳过了测试而又不影响测试结果,则该解决方案会提示自己-您需要测试!



使这项任务自动化的方法是Front Conf的Mark Langovoy的报告。 视频和文章简短,想法很实用-您需要注意。


关于发言人: Mark Langovoimarklangovoi )在Yandex.Tolok项目的Yandex中工作。 这是一个用于快速标记大量数据的众包平台。 客户下载例如需要准备供机器学习算法使用的数据并设定价格,另一方面,执行者可以完成任务并赚钱。

在业余时间,Mark开展了Krasnodar Devodar开发人员日活动,这是19个IT社区之一,我们邀请其活动家参加莫斯科Frontend Conf。

测试中


有不同类型的自动化测试。


在流行的单元测试中,我们为应用程序的小部分(模块)编写测试。 它们很容易编写,但是有时在与其他模块集成期间,它们的行为可能与我们预期的不完全相同。

为避免这种情况,我们可以编写集成测试来一起测试模块的运行情况。


它们稍微复杂一点,所以今天我们将重点关注单元测试。

单元测试


任何至少需要最小稳定性的项目都在编写单元测试。

考虑一个例子。

class Signal { on(callback) { ... } off(callback) { const callbackIndex = this.listeners.indexOf(callback); if (callbackIndex === -1) { return; } this.listeners = [ ...this.listeners.slice(0, callbackIndex - 1), ...this.listeners.slice(callbackIndex) ]; } trigger() { ... } } 

有一个Signal类-这是一个Event Emitter,具有用于订阅的on方法和用于删除订阅的off方法-我们检查回调是否包含在users数组中,然后将其删除。 而且,当然,有一个触发方法将调用签名的回调。

对于此示例,我们有一个简单的测试,先调用on和off方法,然后调用触发器,以验证取消订阅后未调用该回调。

 test('off method should remove listener', () => { const signal = new Signal(); let wasCalled = false; const callback = () => { wasCalled = true; }; signal.on(callback); signal.off(callback); signal.trigger(); expect(wasCalled).toBeFalsy(); }); 

质量评估标准


评估这种测试质量的标准是什么?

代码覆盖率是最流行且最著名的标准,它显示了在运行测试时执行了多少百分比的代码行。


您可能具有70%,80%或全部90%的代码覆盖率,但这是否意味着当您收集下一个版本进行生产时,一切都会好起来,否则可能会出问题?

让我们回到我们的例子。

星期五晚上,您很累,您要完成下一个功能。 然后您会遇到同事编写的这段代码。 关于您的事情对您来说似乎很复杂和令人恐惧。

  ...this.listeners.slice(0, callbackIndex - 1), ...this.listeners.slice(callbackIndex) 

您决定可以清除数组:

 class Signal { ... off(callback) { const callbackIndex = this.listeners.indexOf(callback); if (callbackIndex === -1) { return; } this.listeners = []; } ... } 

我承诺,组装项目并将其发送到生产中。 测试通过-为什么不呢? 然后他在酒吧休息。



但是突然,到深夜,接听电话到了接收器,一切都在下降,人们无法使用该产品,总的来说,企业在浪费金钱! 你烧死了,你有被解雇的威胁。



该如何处理? 做什么测试? 如何捕捉这种原始的愚蠢错误? 谁来测试测试?

当然,您可以雇用QA工程师队伍-让他们坐下来,然后为我们的应用程序鼓掌。



或租用质量检查自动化。 他们可以责怪他们编写测试-如果为此有特殊的人,为什么还要自己编写?

但是实际上它很昂贵,因此今天我们将讨论突变分析或突变测试。

变异测试


这是一种自动化测试过程的方法。 其目的是识别无效和不完整的测试,也就是说,实际上就是测试

想法是更改代码段,对它们运行测试,如果测试没有失败,则说明它们不完整。

使用某些运算进行更改。 例如,它们用减号代替加号,除以乘号以及其他类似运算。 变量器可以更改代码段,在while数组中替换条件,零数组而不是向数组中添加某些元素。


由于对源代码应用了变异,因此它变异并成为变异

突变体分为两类:

  1. 已杀死 -我们能够识别偏差的那些,即至少进行了一次测试。
  2. 幸存者是逃离我们并将虫子带入生产环境的人。

为了评估质量,有一个MSI指标(突变得分指标) -被杀死和存活的突变体的百分比。 代码覆盖率测试与MSI之间的差异越大,代码覆盖率的百分比就越无法反映我们测试的相关性。

这只是一点理论,现在考虑如何在JavaScript中使用它。

Javascript解决方案


JavaScript- Stryker中只有一个正在积极开发的变异测试工具。 该名称是为纪念X-man威廉·史崔克(William Stryker)的角色而命名的。



Stryker不是像Karma或Jest这样的测试跑步者。 它也不是像Mocha或Jasmine这样的测试框架。 这是一个变异测试框架,可对您当前的基础结构进行补充。

插件系统


Stryker非常灵活,完全基于插件系统构建,其中大部分由Stryker开发人员编写。


有用于在Jest,Karma和Mocha上运行测试的插件。 与Mocha(stryker-mocha-framework)Jasmine(stryker-jasmine)框架和现成的针对JavaScript,TypeScript甚至Vue的增变器集集成在一起:

  • stryker-javascript-mutator;
  • 罢工者打字稿;
  • 斯特雷克·维·穆特

stryker-javascript-mutator中包含了React的Mutators。 除此之外,您始终可以编写自己的增变器。

如果需要在运行之前转换代码,则可以使用Webpack,Babel或TypeScript插件。


这一切都相对简单地设置。

构型


配置并不困难:您只需在JSON配置中指定要使用的测试运行程序(和/或测试框架和/或编译器),以及从npm安装适当的插件。

简单的控制台实用程序stryker-cli可以在问答模式下为您完成所有这些操作。 她会问您使用什么,并自行配置。

如何运作


生命周期很简单,包括以下步骤:

  • 读取并分析配置。 Stryker下载配置并分析各种插件,设置,文件排除等。
  • 根据配置下载插件。
  • 在源代码上运行测试,以便立即检查测试是否相关(突然已经损坏)。
  • 如果一切顺利,将从我们允许突变的文件中生成一组突变体。
  • 对突变体进行测试。



上面是启动Stryker的示例:

  • Stryker启动;
  • 读取配置;
  • 加载必要的依赖关系;
  • 查找将变异的文件;
  • 在源代码上运行测试;
  • 创建152个突变体;
  • 在8个线程中运行测试(在这种情况下,根据CPU内核数)。

这不是一个快速的过程,因此最好在某些CI / CD服务器上进行。

通过所有测试后,Stryker会提供有关文件的简要报告,其中包含已创建,杀死和存活的突变体的数量,以及杀死的变异体与幸存者(MSI)以及使用的变异体的百分比。

这些是我们的测试中未预见到的潜在问题。

总结一下


变异测试是有用和有趣的 。 它可以在测试的早期发现问题,而无需人们的参与。 例如,由于合格的开发人员将不必花时间进行拉动请求验证(这已经存在潜在的问题),它将减少拉动请求验证的时间。 如果您决定在星期五晚上准备一个新版本,或保存制作。

Stryker是一种灵活的多线程变异测试工具。 它正在积极开发中,但是到目前为止,还没有达到主要版本。 例如,在编写此报告期间,其开发人员终于使Babel插件可以指定配置文件并修复Jest集成。 这是一个可以帮助开发的开源项目

常见问题
-如何测试变异测试? 当然,也有一个错误。 在第一个单元测试示例中,覆盖率为90%。 看起来一切都很好,但是当一切都倒下并着火时,案件仍在继续。 因此,在涵盖了这些突变测试后,为什么会有种一切都很好的感觉呢?

-我并不是说突变测试是灵丹妙药,它可以治愈一切。 自然,可能会有一些极端的疯狂案例或缺少某种变种人。 首先,容易捕获典型错误。 例如,您对年龄进行了检查,将其设置为<18(这是必需的<=),并且在测试中忘记进行边框检查。 您与mutator进行了另一个比较,结果测试下降了(或没有下降),并且您知道一切都好或坏。 这样的事情很快就被抓住了。 这是一种简单地正确附加测试,查找缺失点的方法。

-您经常会感到“震惊而左”吗? 我认为这是不正确的。

-不,但我认为在许多项目中确实存在这种情况。 自然,这是不正确的。 许多人认为“代码覆盖率”有助于检查所有内容,您可以放心离开而不必担心-事实并非如此。

-我马上说出问题所在。 我们有许多各种各样的异径管和其他我们经过突变测试的东西,其中有很多。 所有这些都在增长,事实证明,对于每个请求请求,都会启动突变测试,这需要很多时间。 是否可以仅在发生变化的地方运行?

“我认为您可以自己配置它。” 例如,在开发人员方面,当他推动并提交时,您可以制作一个仅运行在lint上的插件,该插件仅运行已更改的文件。 在CI / CD上,这也是可能的。 在我们的案例中,该项目非常庞大且古老,我们会进行现场测试。 我们不会检查所有内容,因为要花一周的时间,才会有成千上万的突变。 我建议进行抽查,或者自己组织一个选择性的启动过程。 我还没有看到用于这种集成的现成工具。

-是否确保特定代码的所有可能变异的完整性? 如果没有,如何准确选择突变?

-我个人没有检查,但是我也没有遇到任何问题。 Stryker必须在同一段代码上生成所有可能的变异。

-我想问一下快照。 我的单元测试同时测试逻辑和快照快照组件的布局。 自然,如果我更改任何逻辑设计,我的布局也将在那里更改。 这是预期的行为,不是吗?

-是的,这就是您手动更新快照的含义。

-因此您以某种方式忽略了此报告中的快照?

-最有可能的是,快照需要提前更新,然后运行变异测试,否则Stryker会产生大量垃圾。

-有关CI服务器的问题。 对于简单的单元测试,在GitLab下有报告程序来显示您想要的任何内容,这些报告显示成功测试的百分比,您可以配置是否失败。 斯特赖克呢? 它只是在控制台中显示平板电脑,但是接下来我该怎么办?

-他们有HTML报告程序,您可以创建自己的报告程序-一切都可以灵活定制。 也许有一些特定的工具,但是由于我们仍在进行点突变测试,因此我没有发现与TeamCity和类似CI / CD工具的特定集成。

-变异测试在多大程度上增加了您对一般测试的支持? 也就是说,测试是一种痛苦,并且在重写代码时需要重写测试,等等。有时,重写代码比测试容易。 在这里我也有突变测试。 对于一家企业来说,价格是多少?

-首先,为了测试,我可能会改正代码是错误的。 该代码应易于测试。 至于需要完成的工作,对业务而言再次重要的是,测试应尽可能完整和有效。 如果它们不完整,则意味着可能会发生错误,并带来损失。 自然,您只能测试业务中最重要的部分。

“不过,出现突变测试要比不进行突变测试贵得多。”

-现在就像坏测试一样。 如果测试现在编写得不好,您将不得不添加很多内容。 变异测试将查找测试未涵盖的案例。

“ Stryker测试结果幻灯片上有很多折衷,无论是关键还是不关键。 如何处理误报?

-一个微妙的问题是什么被认为是错误的。 我问团队中的家伙,他们发生了什么有趣的事情。 有一个有关错误文本的示例。 Stryker报告说测试没有响应错误文本的更改。 这似乎是门框,但较小。

-这样您会看到此类错误,并在手动模式下跳过非严重错误?

“我们有一次抽查,是的。”

-我有一个实际的问题。 实施此方法时,您失败了多少百分比的测试?

-我们没有在整个项目中实施它,但是在新项目中存在一些小问题。 因此,我无法透露确切数字,但总的来说,这种方法肯定可以改善这种情况。

在我们的youtube频道上查看其他同样有用的前端表演,我们所有会议的所有主题报告都逐渐到达那里。 或订阅新闻通讯 ,我们将使您随时了解所有新材料和未来会议的新闻。

Source: https://habr.com/ru/post/zh-CN421141/


All Articles