React Native单元测试

举报
SUNSKY 发表于 2019/10/13 14:02:25 2019/10/13
【摘要】 所谓单元测试,就是对每个单元进行的测试,一般针对的是函数、类或单个组件,不涉及系统和集成,单元测试是软件测试的基础测试,一个完备的软件系统都会涉及到单元测试。

概述

所谓单元测试就是对每个单元进行的测试一般针对的是函数、类或单个组件不涉及系统和集成单元测试是软件测试的基础测试一个完备的软件系统都会涉及到单元测试。

目前Javascript的测试工具很多但是针对React的测试主要使用的是Facebook推出的Jest框架Jest是基于Jasmine的JavaScript测试框架具有上手容易、快速、可靠的特点是React.js默认的单元测试框架。相比其他的测试框架Jest具有如下的一些特点

  • 适应性Jest是模块化、可扩展和可配置的

  • 沙箱和快速Jest虚拟化了JavaScript的环境能模拟浏览器并且并行执行

  • 快照测试Jest能够对React 树进行快照或别的序列化数值快速编写测试提供快速更新的用户体验

  • 支持异步代码测试支持promises和async/await

  • 自动生成静态分析结果不仅显示测试用例执行结果也显示语句、分支、函数等覆盖率。

环境搭建

安装Jest

首先在项目目录下使用下面的命令安装Jest。

1.0.png

如果你使用的是react-native init命令行方式来创建的RN项目且RN版本在0.38以上则无需手动安装系统在生成项目的时候会自动添加依赖。

1.1.png

配置Babel

现在很多的项目都使用es6及以上版本编写为了兼容老版本我们可以使用Babel来将es5的语法转换为es6。使用Babel前我们需要使用如下的命令来安装Babel。

1.2.png

说明如果使用的是Babel 的version 7则需要安装babel-jest, babel-core@^7.0.0-bridge.0 和 @babel/core安全命令如下:

1.3.png

然后在项目的根目录里添加 .babelrc 文件在文件中配置如下react-native脚本内容。

1.4.png

如果是自动生成的 .babelrc 文件的配置脚本如下

1.5.png

此时需要将上面的presets配置修改为 "presets": ["react-native"]。

完整配置

为了方便查看 下面是package.json文件的完整配置

1.6.png

说明如果报AccessibilityInfo错误请注意react-naitve的版本号因为react-naitve的版本和其他库存在一些兼容问题请使用0.55.4及以下稳定版本。

1.7.png1.8.png

Enzyme

Enzyme 是 Airbnb 公司开源的测试工具库是react-addons-test-utils的封装的产品它模拟了 jQuery 的 API非常直观并且易于使用和学习提供了一些与众不同的接口和几个方法来减少测试的样板代码方便你判断、操纵和遍历 React Components 的输出并且减少了测试代码和实现代码之间的耦合。相比react-addons-test-utilsenzyme的API 就一目了然下表是两个框架常用的函数的对比。

1.9.jpg

Enzyme提供了三种渲染方法

shallow

shallow 方法就是对官方的 Shallow Rendering 的封装浅渲染在将一个组件作为一个单元进行测试的时候非常有用可以确保你的测试不会去间接断言子组件的行为。shallow 方法只会渲染出组件的第一层 DOM 结构其嵌套的子组件不会被渲染出来从而使得渲染的效率更高单元测试的速度也会更快。例如

1.10.png

mount

mount 方法则会将 React 组件渲染为真实的 DOM 节点特别是在依赖真实的 DOM 结构必须存在的情况下比如说按钮的点击事件。 完全的 DOM 渲染需要在全局范围内提供完整的 DOM API 这也就意味着它必须在至少“看起来像”浏览器环境的环境中运行如果不想在浏览器中运行测试推荐使用 mount 的方法是依赖于一个名为 jsdom 的库它本质上是一个完全在 JavaScript 中实现的 headless 浏览器。 mount渲染方式的示例如下

1.11.png

render

render 方法则会将 React 组件渲染成静态的 HTML 字符串返回的是一个 Cheerio 实例对象采用的是一个第三方的 HTML 解析库 Cheerio。这个 CheerioWrapper 可以用于分析最终结果的 HTML 代码结构它的 API 跟 shallow 和 mount 方法的 API 都保持基本一致。

1.12.png

Jest单元测试

简单示例

首先我们在项目的根目录新建一个名为__test__的文件夹然后编写一个组件例如

1.13.png

然后我们在__test__文件夹下编写一个名为jest.test.js的文件代码如下

1.14.png

使用命令 “yarn jest” 系统就会开始执行单元测试如果没有任何错误将会显示PASS相关的信息。

1.15.png

当然上面的例子并没有涉及到任何的业务逻辑只是介绍了下在React Native中如何使用Jest进行单元测试。

生成快照测试

快照测试是第一次运行测试的时候在不同情况下的渲染结果挂载前保存的一份快照文件后面每次再运行快照测试时都会和第一次的比较除非使用“npm test -- -u”命令重新生成快照文件。

为了测试快照测试我们先新建一个带有逻辑的组件。例如

1.16.png

上面的组件拥有三种状态初始状态点击状态以及再次被点击的状态所以在测试文件中我们分别生成三种状态的快照快照测试文件的代码如下

1.17.png

然后在控制台运行yarn jest命令就会看到在__tests___snapshots_\目录下看到快照测试快照测试文件的代码如下

1.18.png1.19.png

如果需要更新快照文件执行yarn test -- -u命令。

DOM测试

DOM测试主要测试组件生成的 DOM 节点是否符合预期比如响应事件之后组件的属性与状态是否符合预期。DOM 测试 依赖于官方的 TestUtil所以需要安装react-addons-test-utils依赖库安装的时候注意版本的兼容问题。不过在实战过程中我发现react-addons-test-utils会报很多错误并且官方文档也不是很友好。

这里推荐使用airbnb开源的Enzyme 脚手架Enzyme是由 airbnb 开发的React单测工具它扩展了React的TestUtils并通过支持类似jQuery的find语法可以很方便的对render出来的结果做各种断言开发体检十分友好。

生成测试报告

使用命令yarn test -- --coverage就可以生成测试覆盖报告。如图

1.20.png

同时还会在根目录生成一个名为 coverage 的文件夹是测试覆盖报告的网页版包含更多更详细的信息。

Jest基础语法

匹配器

匹配器用于测试输入输出的值是否符合预期下面介绍一些常见的匹配器。

普通匹配器

最简单的测试值的方法就是看值是否精确匹配使用的是toBe()例如

1.21.png

toBe()使用的是JavaScript中的Object.is()属于ES6中的特性所以不能检测对象如果要检测对象的值的话需要用到toEqual。

1.22.png

Truthiness

在实际的测试中有时候我们需要明确区分undefined、null和false等情况而Jest提供的下面的一些规则可以帮我们完成上面的需求。

  • toBeNull只匹配null

  • toBeUndefined只匹配undefined

  • toBeDefine与toBeUndefined相反

  • toBeTruthy匹配任何if语句为真

  • toBeFalsy匹配任何if语句为假

数字匹配器

toBeGreaterThan()大于 toBeGreaterThanOrEqual()大于或者等于 toBeLessThan()小于 toBeLessThanOrEqual()小于或等于 注对比两个浮点数是否相等使用的是toBeCloseTo()而不是toEqual()。

例子

1.23.png

字符串

使用toMatch()函数测试字符串传递的参数需要是正则表达式。例如

1.24.png

数组

如果要检测某个字符串是否包含某个字符串或字符可以使用toContain()。例如

1.25.png

toThrow

如果想在测试特定函数的时候抛出错误则可以在它调用的时候可以使用toThrow()。

异步函数

在实际开发过程中经常会遇到一些异步的JavaScript代码。当有异步方式运行的代码的时候Jest需要知道当前它测试的代码是否已经完成然后它才可以转移动另一个测试。也就是说测试的用例一定要在测试对象结束之后才能够运行。异步测试有多种手段

回调

回调函数和异步没有必然的联系回调只是异步的一种调用方式而已。现在假设一个fetchData(call)函数获取一些数据并在完成的时候调用call(data)我们想要测试返回的数据是不是包含字符串'peanut butter'那么我们可以这样写

1.26.png

Promise

Promise表示“承诺将来会执行”的对象基础内容可以参考廖雪峰的Promise。例如还是上面的fetchData我们使用Promise代替回调来实现网络请求。则测试代码写法如下

1.27.png

上面我们使用expect.assertions来验证一定数量的断言是否被调用如果想要Promise被拒绝我们可以使用.catch方法。

1.28.png

Async/Await

Async/Await是一种新的异步请求实现方式若要编写async测试只需要在函数前面使用async关键字即可。例如

1.29.png

Jest Object

在写测试的时候我们经常需要进行测试之前做一些准备工作。例如多次测试重复设置的工作可以使用beforeEach和afterEach。

1.30.png

在某些情况下如果只需要在文件的开头做一次设置则可以使用beforeAll和afterAll来处理。

1.31.png

作用域

默认情况下before和after的块可以应用到文件中的每一个测试。此外可以通过describe块来将将测试中的某一块进行分组当before和after的块在describe块内部的时候则只适用于该describe块内的测试。例如

1.32.png

Jest测试之Mock

mock测试就是在测试过程中对于某些不容易构造或者不容易获取的对象用一个虚拟的对象来创建以便继续进行测试的测试方法。Mock函数通常会提供以下三种特性

  • 捕获函数调用情况

  • 设置函数返回值

  • 改变函数的内部实现

本节我们主要介绍与 Mock 函数相关的几个API分别是jest.fn()、jest.spyOn()、jest.mock()。

jest.fn()

jest.fn()是创建Mock函数最简单的方式如果没有定义函数内部的实现jest.fn()会返回undefined作为返回值。例如

1.33.png

jest.fn()所创建的Mock函数还可以设置返回值定义内部实现或返回Promise对象。

1.34.png

上面的代码是jest.fn()提供的几个常用的API和断言语句下面我们在src/fetch.js文件中写一些被测试代码以更加接近业务的方式来理解Mock函数的实际应用。

需要说明的是被测试代码中依赖了axios这个常用的请求库和JSONPlaceholder这个上篇文章中提到免费的请求接口请先在shell中执行npm install axios --save安装依赖。

1.35.png

我们在fetch.js中封装了一个fetchPostsList方法该方法请求了JSONPlaceholder提供的接口并通过传入的回调函数返回处理过的返回值。如果我们想测试该接口能够被正常请求只需要捕获到传入的回调函数能够被正常的调用即可。例如

1.36.png

jest.mock(

在上一个请求fetch.js文件夹中我们封装的请求方法可能在其他模块被调用但有时候我们并不需要进行实际的请求请求方法已经通过单侧或需要该方法返回非真实数据。此时使用jest.mock(去mock整个模块是十分有必要的。

1.37.png

然后我们编写一个测试文件用于测试getPostList请求。

1.38.png

测试代码中我们使用了jest.mock('../src/fetch.js')去mock整个fetch.js模块如果注释掉这行代码执行测试脚本时会出现以下报错信息。

1.39.png

jest.spyOn()

jest.spyOn()方法同样可以创建一个mock函数但是该mock函数不仅能够捕获函数的调用情况还可以正常的执行被spy的函数。实际上jest.spyOn()是jest.fn()的语法糖它创建了一个和被spy的函数具有相同内部代码的mock函数。例如

1.40.png

上图是之前jest.mock()的示例代码中的正确执行结果的截图从shell脚本中可以看到console.log('fetchPostsList be called!');这行代码并没有在shell中被打印这是因为通过jest.mock()后模块内的方法是不会被jest所实际执行的。这时我们就需要使用jest.spyOn()。

1.41.png

执行npm run test后可以看到shell中的打印信息说明通过jest.spyOn()fetchPostsList被正常的执行了。

1.42.png

E2E自动化测试

本文转载自异步社区。

原文链接https://www.epubit.com/articleDetails?id=Nbade040a-e501-46c6-974d-f661b39b5a41


【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。