测试Node.js项目。 第2部分。测试性能评估,持续集成和代码质量分析

测试Node.js项目。 第1部分。测试解剖结构和测试类型

今天,在专门用于测试Node.js项目的材料的第二部分翻译中,我们将讨论评估测试的有效性和分析代码的质量。

图片

第三节。测试有效性的评估


19英镑 通过测试获得足够高的代码覆盖率水平,以便对其正确操作充满信心。 通常,大约80%的覆盖率会产生良好的效果。


推荐建议


测试的目的是确保程序员可以继续在项目上进行富有成效的工作,并确保已完成的工作是正确的。 显然,经过测试的代码量越大,则一切正常工作的信心就越大。 测试的代码覆盖率指示器指示测试检查了多少行(分支,命令)。 该指标应该是什么? 很显然,只有10%到30%的比例太小,不足以使该项目能够毫无错误地运行。 另一方面,测试要100%覆盖代码的愿望可能会变得过于昂贵,并且会使开发人员从最重要的程序片段中分散注意力,从而迫使他在代码中寻找现有测试无法到达的地方。 如果您对测试覆盖代码的范围给出更完整的答案,那么我们可以说,我们应努力追求的指标取决于正在开发的应用程序。 例如,如果您正在为下一代空中客车A380编写软件,则100%是一个甚至没有讨论的指标。 但是,如果您创建一个将显示漫画画廊的网站,那么大概50%已经很多。 尽管测试专家说,您应该针对的测试代码覆盖率的水平取决于项目,但其中许多人提到80%的数字,这可能适合大多数应用程序。 例如, 在这里我们谈论的是大约80-90%的范围,根据该材料的作者,测试包含100%的代码覆盖率使他感到怀疑,因为这可能表明程序员编写测试只是为了获得报告中的漂亮数字。

为了使用代码覆盖率测试的指标,您将需要正确配置系统以进行持续集成(CI,Continuous Integration)。 如果相应的指标未达到某个阈值,这将允许停止项目的组装。 这是配置Jest来收集测试覆盖率信息的方法。 此外,您可以不为整个代码配置覆盖率阈值,而可以针对单个组件进行配置。 除此之外,请考虑检测测试覆盖率的降低。 例如,在向项目中添加新代码时,就会发生这种情况。 该指标的控制将鼓励开发人员增加测试代码的数量,或至少将其保持在现有水平。 鉴于上述情况,测试代码的覆盖率只是量化的一个指标,不足以完全评估测试的可靠性。 另外,如下所示,它的高级别还并不意味着“检查中包含的代码”已被真正检查。

偏离建议的后果


程序员对高质量的代码以及与测试相关的相关指标充满信心。 如果程序员不知道自己项目的大多数代码都包含在测试中,那么他将不禁担心错误。 这些问题可能会减慢您的项目速度。

例子


这是典型的测试覆盖率报告的样子。


伊斯坦布尔生成的测试覆盖率报告

正确的方法


这是在Jest中设置所需的组件代码测试覆盖率级别和该指标的一般级别的示例。


通过整个项目和特定组件的测试来设置所需的代码覆盖级别

20英镑。 通过测试检查有关代码覆盖率的报告,以识别未保护的代码部分和其他异常


推荐建议


一些问题倾向于通过各种错误检测系统来解决。 使用传统工具可能很难检测到此类情况。 也许这不适用于实际错误。 而是,我们正在谈论意外的应用程序行为,这可能会带来灾难性的后果。 例如,经常会发生某些代码片段从未使用或很少被调用的情况。 例如,您认为PricingCalculator类的机制始终用于设置产品价格,但实际上事实证明根本没有使用该类,并且在数据库以及使用该系统的在线商店中有10,000种产品的记录,大量销售...有关测试代码覆盖率的报告可帮助开发人员了解应用程序是否按应有的方式工作。 此外,从报告中可以找到未测试的项目代码。 如果您专注于指示测试覆盖了80%的代码的常规指示器,则无法确定是否正在测试应用程序的关键部分。 为了生成这样的报告,足以正确配置用于运行测试的工具。 这样的报告通常看起来很漂亮,而且它们的分析不需要花费很多时间,可以让您发现各种意外情况。

偏离建议的后果


如果您不知道代码的哪些部分仍未经测试,那么您将不知道可能在哪里遇到问题。

错误的方法


查看下一份报告,并考虑其中看起来异常的地方。


报告指出异常的系统行为

该报告基于真实的应用程序使用情况,使您可以查看与用户登录系统相关的异常程序行为。 即,与成功的尝试相比,进入系统的大量失败尝试令人惊讶。 在分析了项目之后,事实证明,原因是前端出错,由于项目的接口部分不断向服务器API发送相应的请求以进入系统。

▍21。 使用变异测试通过测试来衡量逻辑代码覆盖率


推荐建议


传统的基准测试指标可能不可靠。 因此,在报告中可以有一个100%的数字,但是同时,项目的所有功能绝对会返回错误的值。 怎么解释呢? 事实是,测试的代码覆盖率指标仅指示在测试系统的控制下执行了哪些代码行,而不取决于是否已真正验证过某些内容,即是否有测试语句旨在检查代码结果的正确性。 这类似于一个从国外出差返回的人,在他的护照上显示邮票。 邮票证明他去过某个地方,但没有透露他是否出差了。

在这里,变异测试可以为我们提供帮助,这使我们能够找出实际测试了多少代码,而不仅仅是测试系统访问了多少代码。 对于突变测试,可以使用Stryker JS库。 以下是其工作原理:

  1. 她故意更改代码,从而在其中产生错误。 例如,代码newOrder.price===0变成newOrder.price!=0 。 这些“错误”称为突变。
  2. 她进行测试。 如果事实证明它们合格,那么我们就会遇到问题,因为测试无法完成其检测错误的任务,而“突变体”(如他们所说的“生存”)就无法完成。 如果测试表明代码中有错误,则一切正常-“突变体”“死亡”。

如果事实证明所有“突变体”都被“杀死”(或者至少其中大多数没有幸存),那么与传统的度量覆盖测试的指标相比,这给代码和测试它的测试的高质量带来了更高的信心。 同时,配置和进行突变测试所需的时间与使用常规测试所需的时间相当。

偏离建议的后果


如果传统的代码覆盖率指标表明测试覆盖了85%的代码,则这并不意味着测试能够检测到该代码中的错误。

错误的方法


这是一个包含100%测试代码覆盖率的示例,其中该代码完全未经过测试。

 function addNewOrder(newOrder) {   logger.log(`Adding new order ${newOrder}`);   DB.save(newOrder);   Mailer.sendMail(newOrder.assignee, `A new order was places ${newOrder}`);   return {approved: true}; } it("Test addNewOrder, don't use such test names", () => {   addNewOrder({asignee: "John@mailer.com",price: 120}); });//    100%, ,   ,     

正确的方法


这是Stryker库生成的突变测试报告。 它允许您找出未测试的代码数量(这由“存活的”“突变体”的数量指示)。


史赛克报告

该报告的结果使测试的代码覆盖率指标比通常的指标更有信心,可以说测试按预期进行。

  • 突变是由Stryker库故意修改的代码,用于测试测试的有效性。
  • “被杀死”的“突变体”(被杀死)的数量表示在测试过程中识别出的故意创建的代码缺陷(“突变体”)的数量。
  • “幸存的”“突变体”(幸存的)的数量使您可以找出未发现多少代码缺陷测试。

第4节。持续集成,其他代码质量指标


▍22。 利用linter的功能,并在项目检测到报告的问题时中断项目的构建过程


推荐建议


如今,lints是可以识别严重代码问题的强大工具。 除了一些基本的掉线规则(例如,由eslint-plugin-standardeslint-config-airbnb插件实现的规则)外,建议使用专门的规则。 例如,这些是通过eslint-plugin-chai-expect插件实施的规则,以验证测试代码的正确性,这些是eslint-plugin-promise插件中的控制带有承诺的工作的规则,这些是eslint-plugin-security中的规则,用于检查代码是否存在它包含危险的正则表达式。 在这里,您还可以提及eslint-plugin-you-dont-need-lodash-underscore插件,该插件可让您在代码中查找使用具有纯JavaScript类似物的外部库中的方法。

偏离建议的后果


一个下雨天到了,项目使生产连续失败,并且日志中没有有关错误堆栈的信息。 发生什么事了 事实证明,代码抛出的异常并不是真正的错误对象。 结果,有关堆栈的信息不会进入日志。 实际上,在这种情况下,程序员可以要么孤军奋战,要么花5分钟搭建起短绒,这将很容易地发现问题并确保项目免受将来可能出现的类似麻烦的影响。

错误的方法


这是无意中抛出一个普通对象作为异常的代码,而在这里您需要一个Error类型的对象。 否则,有关堆栈的数据将不会进入日志。 ESLint查找可能导致生产问题的原因,从而有助于避免这些问题。


ESLint帮助您发现代码中的错误

▍23。 使用本地持续集成向开发人员提供更快的反馈


推荐建议


使用持续集成的集中式系统,该系统有助于控制代码的质量,使用lint对其进行测试,检查其是否存在漏洞? 如果是这样,请确保开发人员可以在本地运行该系统。 这将使他们能够立即检查其代码,从而加快反馈速度并减少项目开发时间。 为什么会这样呢? 一个有效的开发和测试过程涉及许多周期性重复的操作。 对代码进行测试,然后开发人员接收报告,然后,如有必要,对代码进行重构,然后重复所有操作。 反馈循环的运行速度越快,开发人员接收代码测试报告的速度就越快,他们可以执行的代码改进迭代次数就越多。 如果花费大量时间来获得测试报告,则可能导致代码质量差。 假设某人正在某个模块上工作,然后开始在其他模块上工作,然后收到有关该模块的报告,这表明该模块需要改进。 但是,由于开发人员已经完全解决了完全不同的问题,因此他们将不会对问题模块给予足够的重视。

一些CI解决方案提供商(例如,这适用于CircleCI )使您可以在本地运行CI管道。 一些付费工具,例如Wallaby.js (作者指出他与该项目没有联系),可以快速获取有关代码质量的有价值的信息。 另外,开发人员可以简单地将适当的npm脚本添加到package.json ,以执行代码质量检查(测试,使用lint进行分析,查找漏洞),甚至使用并发程序包来加快检查速度。 现在,为了全面检查代码,足以执行一个命令(如npm run quality )并立即获取报告。 另外,如果代码测试表明它有问题,则可以使用git hook取消提交( 沙哑的库对于解决此问题很有用)。

偏离建议的后果


如果开发人员在编写此代码后的第二天收到有关代码质量的报告,则该报告可能会变成正式文档之类的东西,并且代码测试将脱离工作,而不是自然而然的事情。

正确的方法


这是一个npm脚本,用于检查代码的质量。 执行检查是并行的。 尝试向存储库发送新代码时执行脚本。 此外,开发人员可以主动启动它。

 "scripts": {   "inspect:sanity-testing": "mocha **/**--test.js --grep \"sanity\"",   "inspect:lint": "eslint .",   "inspect:vulnerabilities": "npm audit",   "inspect:license": "license-checker --failOn GPLv2",   "inspect:complexity": "plato .",     "inspect:all": "concurrently -c \"bgBlue.bold,bgMagenta.bold,yellow\" \"npm:inspect:quick-testing\" \"npm:inspect:lint\" \"npm:inspect:vulnerabilities\" \"npm:inspect:license\"" }, "husky": {   "hooks": {     "precommit": "npm run inspect:all",     "prepush": "npm run inspect:all"   } } 

24英镑 在真实的生产环境镜像上执行端到端测试


推荐建议


在广阔的Kubernetes生态系统中,使用适合部署本地环境的工具仍然存在共识,尽管此类工具经常出现。 这里一种可能的方法是使用MinikubeMicroK8s之类的工具运行“最小化” Kubernetes ,使您可以创建类似于真实环境的轻量级环境。 另一种方法是在远程“真实” Kubernetes环境中测试项目。 一些CI提供程序(例如Codefresh )使得与Kubernetes内置环境进行交互成为可能,这简化了在测试实际项目时CI管道的工作。 其他允许您使用远程Kubernetes环境。

偏离建议的后果


在生产和测试中使用各种技术需要两个开发模型的支持,并导致程序员和DevOps专家团队的分离。

正确的方法


这是CI链的示例,正​​如他们所说的那样,它会动态创建一个Kubernetes集群( 从此处获取 )。

 deploy: stage: deploy image: registry.gitlab.com/gitlab-examples/kubernetes-deploy script: - ./configureCluster.sh $KUBE_CA_PEM_FILE $KUBE_URL $KUBE_TOKEN - kubectl create ns $NAMESPACE - kubectl create secret -n $NAMESPACE docker-registry gitlab-registry --docker-server="$CI_REGISTRY" --docker-username="$CI_REGISTRY_USER" --docker-password="$CI_REGISTRY_PASSWORD" --docker-email="$GITLAB_USER_EMAIL" - mkdir .generated - echo "$CI_BUILD_REF_NAME-$CI_BUILD_REF" - sed -e "s/TAG/$CI_BUILD_REF_NAME-$CI_BUILD_REF/g" templates/deals.yaml | tee ".generated/deals.yaml" - kubectl apply --namespace $NAMESPACE -f .generated/deals.yaml - kubectl apply --namespace $NAMESPACE -f templates/my-sock-shop.yaml environment: name: test-for-ci 

25英镑 努力使测试执行并行化


推荐建议


如果测试系统井井有条,它将成为您忠实的朋友,一天24小时随时准备报告代码问题。 为此,必须非常快速地执行测试。 实际上,事实证明,以密集使用处理器的方式在单线程模式下运行500个单元测试会花费太多时间。 而且此类测试需要经常执行。 幸运的是,用于运行测试的现代工具( JestAVAMocha扩展 )和CI平台可以使用多个过程并行运行测试,这可以显着提高接收测试报告的速度。 一些CI平台甚至知道如何在容器之间并行化测试,从而进一步改善了反馈循环。 为了成功并行执行本地或远程测试,测试不应相互依赖。 独立测试可以在不同的进程中运行而不会出现问题。

偏离建议的后果


在使用新项目功能时将代码发送到存储库一小时后获得测试结果是减少测试结果有用性的好方法。

正确的方法


由于测试的并行执行, mocha-parallel-test库和Jest框架可以轻松绕过Mocha( 这是此信息来源)。


测试性能测试工具

▍26。 通过使用许可证验证和窃代码验证来保护自己免受法律问题的侵害


推荐建议


也许现在您并不特别担心法律和窃问题。 但是,为什么不检查您的项目是否存在类似问题? 有许多工具可以组织此类检查。 例如,它们是许可证检查程序窃检查程序 (这是一个商业软件包,但是可以免费使用)。 很容易将此类检查集成到CI管道中并检查项目,例如,是否存在具有有限许可证的依赖项,或者是否存在从StackOverflow复制的代码,并且可能侵犯了他人的版权。

偏离建议的后果


开发人员可能会不经意地使用不适合其项目的许可证使用该程序包,或复制商业代码,这可能会导致法律问题。

正确的方法


在本地或CI环境中安装许可证检查程序软件包:

 npm install -g license-checker 

我们将随它一起检查许可,如果他发现不适合我们的内容,我们将认为支票不成功。 CI系统在检查许可证时检测到出了问题时,将停止项目组装。

 license-checker --summary --failOn BSD 


许可证检查

27英镑 不断检查项目中是否存在易受攻击的依赖项


推荐建议


甚至受尊敬且可靠的软件包(例如Express)也存在漏洞。 为了识别此类漏洞,您可以使用特殊工具-例如,用于审核npm软件包的标准工具或具有免费版本的商业snyk项目。 这些检查以及其他检查可以成为CI管道的一部分。

偏离建议的后果


为了在不使用特殊工具的情况下保护项目免于依赖项的漏洞,您将必须不断监视有关此类漏洞的发布。 这是一项非常耗时的任务。

正确的方法


这是使用NPM Audit进行项目验证的结果。


漏洞检查包报告

28英镑 自动依赖更新


推荐建议


通向善意的道路铺平了道路。 这个想法完全适用于package-lock.json ,默认情况下,该package-lock.json的使用会阻止软件包更新。 即使在通过npm installnpm update命令使项目进入正常状态的情况下,也会发生这种情况。 最好是导致使用过时的软件包,或者最坏的情况是导致项目中易受攻击的代码出现。 结果,开发团队要么依赖于有关包的适当版本的信息的手动更新,要么依赖于ncu之类的实用程序,它们又是手动启动的。 依赖关系的更新过程最好自动执行,重点是使用项目中使用的软件包的最可靠版本。 这不是唯一正确的解决方案,但是,在自动化程序包更新中,有两种值得注意的方法。 第一种方法是使用CIPM管道使用npm-outdatednpm-check-updates (ncu)检查软件包的内容注入 。 这将有助于识别过时的软件包并鼓励开发人员对其进行升级。 第二种方法是使用商业工具来检查代码并自动发出旨在更新依赖关系的请求。 在自动依赖项更新领域,我们面临着另一个有关更新策略的有趣问题。 如果使用每个新修补程序进行更新,则更新可能会对系统造成太大的压力。 如果在发行该软件包的下一个主要版本之后立即进行更新,则可能导致项目中使用不稳定的解决方案(许多软件包中的漏洞恰好在发行后的头几天被发现, 使用eslint-scope 阅读有关此事件的信息)。 « », , . , 1.3.1, 1.3.2, 1.3.8.


, , , .


ncu , , , .


ncu

▍29. , Node.js



, Node.js-, , Node.js .

  1. . — , , , Jenkins .
  2. , Docker.
  3. . , , . (, ), , , , .
  4. , , , . — , , , .
  5. , . , feature, — master, , ( ).
  6. . , .
  7. .
  8. (, Docker) .
  9. , , , . , node_modules .


, , .

▍30.



, . , , , Node.js , . CI-, , « ». , , , . , , mySQL, — Postgres. , Node.js, — 8, 9 10. , . CI-.


, , , . , , .


CI- Travis Node.js.

 language: node_js node_js: - "7" - "6" - "5" - "4" install: - npm install script: - npm run test 

总结


, , . , , .

亲爱的读者们! ?

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


All Articles