大家好,我的名字叫Yaroslav Astafiev,今天我想进行一次有指导的测试ReactJS之旅。 我不会深入研究使用某些库测试Web应用程序的复杂性(以“很难仅测试不良代码的方法”为指导),作为回报,我将尝试使您的视野多样化。 因此,在本文中,React更是将测试方法放在一起的机会,这是将赶时髦的人和技术结合在一起的起点。 甚至说我们将通过ReactJS上的插图来讨论测试的原理,这将是更正确的(不仅如此)。
如果您认为自己是测试专家,请
跳过本文的前半部分 ,它是关于测试的基本原理的。 如果第二部分没有为您显示任何新内容,请找我们工作并教怎么做。

如果介绍没有引起联觉发作,欢迎来猫。
单元测试
Unit Jest是用于测试JavaScript的库。 不喜欢这样-再选
一个 ,但
Ava更好。 一切都很简单:单击魔术按钮,并确保某个值从“ 0”更改为“ 1”:
import React from "react" import { MyButton } from "../src/components/dummy/myButton" import renderer from "react-test-renderer" test("MyButton has onPress fn", () => { let x = 0 const instance = renderer .create(<MyButton onPress={() => x++} />) .getInstance() expect(instance.handlePress).toBeDefined() expect(x).toBe(0) instance.props.handlePress() expect(x).toBe(1) })
现在,您具有测试魔术按钮的
所有必要技能 。 不幸的是,这些技能与现实生活无关。 React组件不能很好地绝缘,隔离是单元测试的主要原理之一。 以某种方式,有必要删除以某种方式参与render方法的所有组件,但已测试的组件除外。 有一个解决方案:聪明的人为此想出了模拟API。
Mock的本质很简单:
Mock / Stub / Fake / Dummy / Spy等不是我们的所有。 我们在预先准备的测试数据上“模仿”我们需要组件的实际行为的方式,该行为可能具有复杂的逻辑,并相信如果输入正确的参数,所有被仿真的组件都可以正常工作。
有一个用于
jest的
jest-fetch-mock库,您可以在其中全局定义moki。 如果您不喜欢此选项,则可以分别“润湿”测试中需要的每个组件。
同一输入上的
纯函数始终返回相同的答案。 因此,如果在我们的业务逻辑中组件具有“不干净的”功能/组件,那么在单元测试中也将需要“清除”(但对于单元测试,此规则并不总是正确的)。 一个经典的例子是一个react组件,它以您需要的格式显示当前日期和时间,每次运行测试时,日期都会不同,并且您将无法编写正确的单元测试。 对于所有不同意的人,您可以使示例复杂化,在该示例中,组件应以相对格式显示日期,并以红色突出显示比
当前日期早
一年的日期。
因此,如果您有依赖于时间/天气/压力的动态事物,那么模拟将重新定义您需要的呼叫,以便不依赖第三方因素。 因此,您不必等待
2月29日才能参加失败的考试。
单元测试规则
上述问题和解决问题的方法是尝试一种非正式的测试方法:每个测试都可以根据需要运行。 我认为,遵守
三个重要的单元测试规则就足够了:
规则一:所有测试都必须是确定性的。 如果我在Windows上编写了一个测试,那么在Mac上它也应该启动并产生相同的结果。 Windows开发人员喜欢忘记* nix系统上的文件名区分大小写。 如果
测试属于CI框架,而不是生产环境中的应用,您将很幸运。
下一个规则是隔离。 我们润湿了所有未经测试的组件。 如果很难做到,那就该重构了。
最后但并非最不重要的一点:如果您的应用程序在运行时接收到数据,则还需要确定它们。 这可以是语言环境,窗口大小,日期格式,浮点数格式等。
整合测试
在我看来,
何时开始编写集成测试是一个悬而未决的问题,并且在每个团队/产品中都应考虑内部因素来做出决定。
您可以采取一种正式的方法:达到
80%的单元测试覆盖率(不良的书面测试不应被审查/测试只要求包含新的或更改的代码),然后对所有书面测试进行全面审核和重构,并分析典型错误,正式制定用于编写测试的内部规则,以及每年进行这样的突袭。 如果经过上述所有操作后,您的单元测试代码覆盖率仍然是80%+,那么您的团队已经成熟,或者您根本不批评代码/测试。 如果代码覆盖率变小,那么您需要再次达到80%的覆盖率并继续编写集成测试。 您可以不那么正式地提出问题,而只需遵循常识即可:例如,对于已播放过n次的每个错误,编写测试或提出其他建议(例如扔硬币)。
第二个开放性问题:
哪些测试被视为集成 ? 也许不要回答。

在集成测试中,我们测试的不是一个组件,而是一堆中的多个组件。 没有规则,但常识告诉您:
- 不要测试它的渲染方式,调用位置以及何时结束。
- 不要测试ReactJS的工作,如果它不起作用,没有任何帮助。
- 不要测试状态机React的工作方式;
- 测试业务逻辑/数据模型/边界情况/经常中断的内容。
在此类测试中,您不应详细介绍。 它们的运行时间明显更长,并且编写它们也更加困难,因此,您不应迷失方向并涵盖应用程序逻辑中的所有次要情况。 就基础架构租赁而言,这是昂贵的,而就开发和脚本执行时间而言,则是很长的。 有人会在这个例程上度过一生,而
用户管理器会很伤心 ,等待新功能,然后...
您不应该尝试测试所有内容的另一个原因是“错误安全性”(我已尝试在上面写下最重要的要点)。 每个团队都应阅读第一类和第二类错误,即诺伊曼-皮尔逊引理,并从金钱,鹦鹉或其他接受团队接受的真实性角度评估其风险。
但是该规则以及任何其他规则都有例外。
忘记上面所说的一切 :
- 测试动态依赖项时。 当您不知道哪个组件会在运行时出现时,可以渲染它,但可能不会出现。 您还需要为此编写一个测试,没有人取消电路制动器。 您预期的组件错误,或者组件损坏。 因此,在这种情况下,我们编写集成测试并进行渲染。 我们检查是否一切正常,如果没有落下。
- 使用完美像素(您知道),开发将不得不渲染和差异屏幕截图,并且每次将组件库更新到新版本时,都要更新参考屏幕截图。 因为
雇用新设计师进行调和比修复容易。
快照测试
最简单的集成测试是快照:
- 我们拿一个组件,渲染它
- 在渲染器中,我们编写console.log(此)
- 从控制台复制参考数据
- 比较一下
如果您想让自己感到困惑,那么我建议您使用
StoryBook库。 这是一个用于快照测试的库,它附带了
StyleGuidist的思想-基于React组件创建您自己的设计系统。
快照测试的第一条规则:
从不告诉,请尝试测试数据 。 它们应该始终是静态的,“锁定的”和独立的。 第二条规则:
快照测试损坏并不意味着一切都不好 。 如果他是红色的-事实并非一切顺利。 有很多选项可以使布局相同,但是DOM树不同。 因此,我们会忽略空格,属性,键,或者我们不会测试需要那么多支持时间的内容。 或者我们用手标记出什么是坏的,什么不是。 我们修复了损坏的测试,并以模拟更新模式(该模式将测试组件渲染并在预期条件下插入Snapshot作为参考值)重新启动StoryBook。
xState和React自动机
ReactJS是一件棘手的事情。 图书馆似乎很酷。 我制作了三个组件-一个类:状态机似乎可以工作并且代码很漂亮。 然后用ReactJS编写六个月,然后看一下代码-有点废话。 您不了解拐杖在哪里,路线在哪里,州在哪里,缓存在哪里...然后您会想到:嗯,我会按照Facebook的建议去做:我会扣好“曲棍球”,“钩子”等其他东西,突然发现自己在想自己的毛呢。 ru试图从头开始寻找一个具有开发能力的项目,因此
肯定可以做得很
漂亮 。
一切都很复杂,以至于通常无法理解其工作原理。 它一直有效,直到有人抱怨为止。 我们对其进行了修复-并且它进行了修复,但是仍然存在问题。...其中一个输出是状态
机 ,一组确定性应用程序状态以及它们之间的允许转换。 而且,正如他们在狭窄的圈子中所说的那样,如果您没有给状态机加油,那么您就不会在反应上写东西。
值得回忆
一下xState 。 这是JavaScript的确定性状态机。
您可以在
xState上
创建非常酷的
UI-可以在
React Automata库的文档中找到指向相应报告的链接。 反过来,React Automata是在ReactJS中修改了xState的库。 此外,她还能够为
状态机的状态生成测试 。
如果我们的第一个复选框为true-绿灯亮。 如果第二个为假,则绘制一条灰狗,React Automata将为这些参数的所有四个组合生成测试,并验证该狗和灯泡。 没错,有时候您会希望减少一半的测试,但起初您会很高兴...无论如何,这是从侧面方便地查看您的测试,它使我非常想起确定性混乱测试的想法。
柏树
有了快照,我们或多或少地发现了,您可以迈向end2end。 我们内部拥有所有产品,因此本地解决方案是我们的唯一选择。 我希望您有机会使用云解决方案,然后像
赛普拉斯这样的事情会派上用场。

以前,您选择了测试框架,使用了用于声明的库,使用库来比较复杂的XML。 然后,我们选择了一个驱动程序和一个浏览器来启动所有程序。 他们开始写了很多测试。 所有这些都吞噬了基础设施,您需要将所有内容塞进docker,然后拧一些东西来查看动态测试,对其进行分析,显示出什么问题...

赛普拉斯的家伙为您做了这一切。 他们解决了几个问题:
设置工作环境,编写代码,运行和编写测试。 如果测试失败,则可以显示屏幕截图,突出显示已损坏的内容。 的确,它不适用于手机,但是例如
Detox 。 从入口阈值的角度来看,这当然是困难的:您将必须针对它定制应用程序,重写一堆文件等。 但是,如果您愿意,那是可能的。
软测试
有其他测试类型也不能称为良好测试。 我称它们为软测试。 例如,短绒棉。 它们主要用于前端(甚至有时灵感来自于骑手)。 有很多
linter :
ESLint ,
JSHint ,
Prettier ,
Standard ,
Clinton 。 我建议
Prettier:快速,便宜,开朗,易于配置,开箱即用 。
如果您想弄糊涂,可以配置ESLint。 让我给他一个经典的插件示例:当客户在代码中发现带有淫秽表达的注释时,他通常会发誓。 棘手的开发人员用俄语发表评论,以便客户不要猜测。 但是客户猜到了……使用Google翻译器,发现了开发人员对他的一切想法。 解决该问题的方法令人不快,可能会造成金钱或客户损失。 对于这些情况,
您始终可以为ESLint开发一个插件 ,该
插件会在源代码中找到“本机俄语”字样,并说:“哦,抱歉,拒绝您的提交。”
JavaScript中的linters的优点在于
可以将它们
放在pre commit钩子上 。 就个人而言,我不喜欢Prettier不会存储历史记录(尽管另一方面,它也不会积累技术债务)。 从代码的统计分析的角度来看,此类测试很麻烦,因为您看不到项目的动态,因此请查看昨天,前天有多少错误。 原则上,此问题在
SonarQube中解决,也在云解决方案中解决。 这是一个统计代码分析器,它存储运行的历史记录,可以使用两种语言,甚至包括PHP(还有其他不需要静态分析的铁手?:)的语言。 在其中,您可以观察漏洞,漏洞,技术债务等的动态。
复杂度测试
前端使用
短绒是因为他们想要漂亮的压痕 。 复杂度也是一项软测试,您可以尝试使用它来检查代码的质量。
该图显示了我如何遵循下级提出拉取请求的想法。 在这种情况下,我建议拆除一切并修建一条直接道路。复杂度测试遵循一个非常简单的原理:它们计算算法的
循环复杂度 。 例如,他们读取一个函数,并在其中找到10个变量。 如果10-可能很难。 让我们设置复杂度1.对于每个循环,我们将为一个循环中的每个循环给出3分-9,对于一个循环中的每个循环将给出27分。我们将所有内容相加并说:循环复杂性为120,一个人只能理解6。此评估的含义是主观地说出何时需要重构源代码,将其分解,突出显示新功能等。 是的,SonarQube也可以做到。
替代测试
在我的世界中,替代测试也适用于软测试。
团结对于入职非常有用。 尽管它是用JavaScript编写的,但不仅适用于前端。 它允许您
测试工作环境 。 以前,有必要编写大量指令,指出编程语言的版本,库,必要的软件列表,以便开始使用,使所有内容保持最新状态等。 现在我们可以这样说:“这是您的计算机,这是源代码。 在
团结过去之前 ,不要来。” 同时,进入阈值较低。 团结可以为自定义工作环境提供指纹,并允许您添加非常简单的规则以不仅验证安装的软件。 当他们想到以下字眼时,这会激怒您:“哦,对不起,那里的某些东西对我不起作用,您能帮忙吗?..”
第二个用例(主要是用例)是使用以下单词
测试生产环境 :“ CI的单元测试确实通过了,但是CI和PROD的配置差异很大。 所以没有任何保证……”。 该库的目标非常简单:实现持续集成的第一条规则:“每个人都应具有相同的环境”。 干净,隔离,以便没有副作用,或者至少没有副作用...我想欺骗谁?
API调用
碰巧的是,开发人员分为几个团队-有些写前端,有些写后端。 一个虚构的情况,不可能出现在一个真正的团队中:昨天一切正常,今天在前后发行两个版本之后一切都破裂了。 谁该怪? 作为最初有后端经验的人,我总是说:前端。
很简单,他们像往常一样把地方弄乱了。 某一时刻,前端供应商会说:“在这里,我们通过
引用阅读了这篇文章,通读了指南,并
学习了如何投射REST API 。 而且您不会相信它已经改变了……” 通常,如果您的后端不是Swagger,openAPI或其他类似解决方案的朋友-值得一提。
性能js
最后,是性能JS测试。 除了浏览器制造商,
没有人在测试性能JS 。 通常,它们都使用
Benchmark.js 。 “哦,我们已经开发了18年的Explorer,以便它比Chrome浏览器更快地显示十亿分之一的平板电脑。” 谁需要这样的平板电脑?
如果您想进行性能测试,则最好采用另一种方法:端到端测试并观察其工作原理。 用户对应用程序整体上的工作方式形成了看法,
用户并不关心这些是后端方面的问题。战争故事1
现在是生活中的一个例子。 老板莫名其妙地找我们说:“您的前线工作非常糟糕,几乎没有负载。 人们抱怨说,表演需要做些事情。” 我们认为:现在我们将有两个星期的时间来执行调优,选择日志记录
为什么要更新 ,选择树摇晃,通过动态加载将所有内容切成碎片...如果它没有耗尽,那么我们将全部分解或变得更糟吗? 需要制定替代解决方案。
我们打开浏览器,看起来:7.5 MB,2秒,一切都很好。
放入Nginx GZip:

Nginx可以调整压缩率,让我们尝试:

增长-生产率的25%。 早点停下来 看看角落里的小设计师徽标。 即使被拉伸,它仍然非常漂亮,但是为什么我们需要它呢?

这是优化一张图片后得到的。 您可以自己评估徽标的重量。 最后,我们拜访客户说:“第一次下载不如第二次下载重要。 并且,启用强制缓存:

...每个人都快乐,每个人都欢腾!” 当然,除了用户。
因此,我们决定更频繁地进行规模审核。
Gzip,字体,图片,样式 -很少有人看到的地方,但有很多好处。
Madge和updtrJS
下一步:
依赖项审核 。
Madge就是这样的东西,它分析代码并说:这是某某某某类与某某某某等相关的类。 如果一切都通过一个组成部分而破裂,那么将不会有什么令人愉快的事情。 Madge是出色的可视化工具,但仅适用于手动探索。 它有一个循环选项,可搜索项目中的所有
循环依赖项 。 如果有的话,那是不好的,如果没有的话,那还没有写。
使用
updtrJS几乎可以解决传统框架和库的
难题 。
您有7万行代码吗? 您是否正在尝试从第13个React移到第16个?
Updtr不会帮助您迁移,但是会帮助您确定可以迁移到哪些版本的库而不会
造成严重后果 。 此外,它还使开发人员能够保持最新趋势,有助于保持最新的依赖性。 如果您具有良好的测试覆盖率,我建议。
静态类型
使用JS静态类型 ,因为
JS动态类型根本不是功能,而是一个深渊。 流,TypeScript,reasonML就是全部...
混沌测试
混乱测试的本质很简单:启动浏览器并开始戳戳所有内容,输入在所有字段中输入的所有内容,依此类推。 直到它破裂。 Amazon, exceptions . , « , ». , . :
Gremlin.com Chaos Monkey .
React — 16- , componentDidCatch. , exception, . .
Naughty String , , . , « », internal server error, ?

War Story #2
– . . def generateRandomPostfix(String prefix) { return prefix + "-" + Math.abs(new Random().nextInt()).toString() } def "testCorrectRandomPostfix"(){ given: def prefix = "ASD" when: def result = generateRandomPostfix(prefix) then: result?.matches(/[a-zA-Z]++-[0-9]++/) }
. . , .
. ASD, , . . ( , groovy). Java integer 1 integer. integer integer — .


, . . ? «+» fromX. , - , XML .
.
.
TestCheck.JS — . , , . —
Flow-To-Gen : Flow , .
check( property( gen.int, gen.int, (a, b) => a + b >= a && a + b >= b ) )
{ result: false, failingSize: 2, numTests: 3, fail: [ 2, -1 ], shrunk: { totalNodesVisited: 2, depth: 1, result: false, smallest: [ 0, -1 ] } }
TestCheck « », . , . , , : 0 -1. 2 -1, , . !
. . , . , ? -? permission'? ? , , , , .
3rd party failures . „ “ — .
Production-
production 16- React :
ErrorCeption HoneyBadger (
Sentry ). ,
.Optimizely /-. , , , , , .
Out of the box
JS — . , JavaScript. —
validator.w3.org/checklink . , , , , .
, , .
Achecker.ca/checker .
Webpagetest.org — , .
Tools.pingdom.com — .
www.w3.org/WAI/ER/tools .
. . , Jenkins Multibranch Plugin, - -. -, (« , »), nightly-, - regress, full regress, smart regress ..
— , , , , . , , , .
, , . .