内容简介:Jest 是 Facebook 发布的一个开源的、基于 Jasmine 框架的 JavaScript 单元测试工具。Enzyme 是 React 的测试类库。 Enzyme 提供了一套简洁强大的 API,并通过 jQuery 风格的方式进行DOM 处理,开发体验十分友好。首先,使用
Jest、Enzyme 简介
Jest 是 Facebook 发布的一个开源的、基于 Jasmine 框架的 JavaScript 单元测试工具。
Enzyme 是 React 的测试类库。 Enzyme 提供了一套简洁强大的 API,并通过 jQuery 风格的方式进行DOM 处理,开发体验十分友好。
普通方法测试
首先,使用 npm
安装Jest
npm install --save-dev jest
在目录下新建一个待测试文件 sort.js
。
function sort(sortArr) {
return sortArr.sort((a, b) => a - b);
}
module.exports = sort;
此处sort方法未对入参做类型检测
在这里定义了一个数组 排序 方法,下面来书写其测试用例,在目录下新建一个 sort.test.js
文件。
const sort = require('./sort');
const arr = [5,2,4,3,1];
test('排序数组[5,2,4,3,1]', () => {
expect(sort(arr)).toEqual([1,2,3,4,5]);
})
在用例中,我们先引入了待测试的方法,接下来定义了一个排序数组[5,2,4,3,1]的测试用例. test()
用来定义一个测试用例, expect()
会执行内部的方法,返回一个待测试的结果。 toEqual()
用来判断返回的结果于期望的结果是否相等。这里由于期望返回结果为数组,所以使用 toEqual
进行判断,除此之外,还有 toBe()
, toBeNull()
等方法来比较不同的类型。 更多内容...
打开 package.json
,在 scripts
中新增
test: "jest"
然后运行命令
npm run test
会看到用例测试通过的信息
<img src=" https://github.com/ISummerRai... ; width="600" />
由于我们的方法没有做入参类型检测,下面通过传入字符串,来测试异常情况。在 sort.test.js
中新增一个测试用例用例
test('排序字符串“52431”', () => {
expect(sort('52431')).toEqual(12345);
})
运行,则会看到测试失败的信息
<img src=" https://github.com/ISummerRai... ; width="600" />
从测试结果中我们可以清除的看到,运行来两个测试用例,第一个用例通过来,第二个用例运行是js出现了报错。此时便能根据测试结果,调整代码
更多测试方法此处不做讨论,具体可以参考 Jest文档
+ 在具体项目中的使用
下面来在实际的项目中使用Jest + Enzyme来进行测试。 测试Demo项目
首先,使用 Create-React-App
来创建一个应用。
接着,安装jest
npm install --save-dev jest
由于在书写用例时,会用到es6语法,所以还要安装 babel-jest
来进行转码
npm install --save-dev babel-jest
安装enzyme
npm install --save-dev enzyme
也可以使用react官方测试插件 react-addons-test-utils
,此处我们使用enzyme,故不需要安装。
此外,还需要根据使用的react版本来安装 enzyme-adapter-react
。具体版本对照如下
| enzyme-adapter-react版本 | react版本 | ||
|---|---|---|---|
enzyme-adapter-react-16
|
^16.4.0-0
|
||
enzyme-adapter-react-16.3
|
~16.3.0-0
|
||
enzyme-adapter-react-16.2
|
~16.2
|
||
enzyme-adapter-react-16.1
|
`~16.0.0-0 \ | \ | ~16.1` |
enzyme-adapter-react-15
|
^15.5.0
|
||
enzyme-adapter-react-15.4
|
15.0.0-0 - 15.4.x
|
||
enzyme-adapter-react-14
|
^0.14.0
|
||
enzyme-adapter-react-13
|
^0.13.0
|
此处demo使用的 react
版本为 ^16.4.1
,所以我们需要安装 enzyme-adapter-react-16
npm install --save-dev enzyme-adapter-react-16
依赖安装完成,接下来需要进行相关的配置。
首先配置package.json的测试命令 test: "jest"
。
此时如果我们在根目录下创建一个 .test.js
文件,并书写简单的方法用例,执行测试命令,是可以正常执行测试用例的。但是,我们的项目却并不是简单的单个方法但测试,实际项目中会存在这大量的组件依赖,还有 css
, image
等静态资源的处理。所以,还要进行如下配置处理。
首先,我们在 package.json
文件中新增一个 jest
的配置项
jest: {}
这里我们主要进行三个配置。
-
moduleFileExtensions代表支持加载的文件名。此处我们的测试文件均以.js结尾,所以只配置成["js"]即可 -
transform用于编译 ES6/ES7 语法,需配合 babel-jest 使用 -
moduleNameMapper代表需要被 Mock 的资源名称。如果需要 Mock 静态资源(如less、scss等),则需要配置 Mock 的路径
jest默认会检索项目内的 *.test.js
, *.test.jsx
形式的文件并执行。当编写当用例没被jest检索到时,可通过 moduleDirectories
来配置路径。
在具体到组件测试时,为了测试组件到交互性,我们需要jest渲染出组件进行操作,此时,由于我们到项目中大量使用来 webpack
到依赖管理,以及 less-loader
、 url-loader
等预编译。在jest渲染组件是,无法识别这些 .less
等文件。所以我们需要通过 mock
来处理这些静态文件。因为jest在渲染组件时,是不需要依赖 css
, image
等静态资源的。所以我们可以这样配置:
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js"
前面通过正则来适配我们需要匹配的静态文件,后面为我们通过mock返回的数据。这里我们还需要在根目录中创建 __mock__
的文件夹。在里面新建 fileMock.js
和 styleMock.js
两个文件。
<!--fileMock.js-->
module.exports = 'test-file-stub';
<!--styleMock.js-->
module.exports = {};
这样就可以将测试集中在组件的结构和逻辑上。另外,可能在我们的项目中,会使用大量的别名来简化引用路径,及webpack中的 alias
配置。此处同样需要进行别名的配置,配置方式与静态资源配置类似。一下是完整配置
"jest": {
"moduleFileExtensions": [
"js",
"jsx"
],
"moduleDirectories": [
"src",
"node_modules"
],
"transform": {
"^.+\\.js$": "babel-jest"
},
"moduleNameMapper": {
"^components(.*)$": "<rootDir>/src/components$1",
"^pages(.*)$": "<rootDir>/src/pages$1",
"^utils(.*)$": "<rootDir>/src/utils$1",
"^services(.*)$": "<rootDir>/src/services$1",
"^static(.*)$": "<rootDir>/src/static$1",
"^models(.*)$": "<rootDir>/src/models$1",
"^variable(.*)$": "<rootDir>//src/static/less/variable.less",
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
"\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js"
}
}
接下来创建一个待测试的组件,在 src > pages
文件夹中创建 login
组件,并配置好路由。组件代码参考 测试Demo项目
运行后页面如下
<img src=" https://github.com/ISummerRai... ; width="320" />
接着,定义测试用例,此Demo定义来八个测试用例如下
- 1、页面title显示“登录”(UI)
- 2、登录账号输入手机号或邮箱时,账号上方显示登录账号
- 3、登录账号输入不为手机号或邮箱,账号上方显示【账户输入错误,请重新输入】
- 4、账号输入正常,密码小于6位,登录按钮置灰。
- 5、账号输入异常,密码不小于6位,登录按钮置灰。
- 6、账号输入正常,密码不小于6位,登录按钮可点。
- 7、点击密码后眼睛图标,显示密码。
- 8、显示密码状态,再次点击,隐藏密码。
接下来,新建文件 login.test.js
来编写测试用例代码。
由于用例中设计多个交互,所以我们需要先渲染出组件。Enzyme为我们提供来三种渲染组件的方法 shallow
、 render
、 mount
。
shallow render mount
三种方法中, shallow
render
返回的为对象,用于分析HTML结构,所以无法用于交互测试。 mount
方法加载的为真实的DOM节点,所以可用于交互测试。本 Login
组件存在大量交互测试,所以使用 mount
创建组件,使用 mount
需要先使用 Adapter
配置如下
import Login from 'pages/Login';
import React from 'react';
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import { mount } from 'enzyme';
configure({ adapter: new Adapter() });
const wrapper = mount(<Login />);
现在,我们就可以使用 Enzyme
的API来编写测试用例了, Enzyme
提供了丰富的类 jquery
风格的API,下面是部分API
.get(index):返回指定位置的子组件的DOM节点
.at(index):返回指定位置的子组件
.first():返回第一个子组件
.last():返回最后一个子组件
.type():返回当前组件的类型
.text():返回当前组件的文本内容
.html():返回当前组件的HTML代码形式
.props():返回根组件的所有属性
.prop(key):返回根组件的指定属性
.state([key]):返回根组件的状态
.setState(nextState):设置根组件的状态
.setProps(nextProps):设置根组件的属性
完整API参见 Enzyme API
在前半部分的demo中,我们使用来 test()
方法来编写用例,此处,我们使用
describe('', () => {
it('', () => {})
})
来编写测试用例,这样我们可以对测试用例进行分组
让我们来开始第一个用例“页面title显示「登录」”的编写
it('标题显示', () => {
const title = wrapper.find('.title').text();
expect(title).toBe('登录');
})
这个用例十分简单,仅仅在第一步获取到了 title
中的文本,并对文本进行校验。
第二个和第三个用例为对输入框输入文本对校验,此处,我们可以单独对校验方法进行测试,也可以页面对交互来完成测试。这里用例通过交互来进行测试用例对编写。由于在输入信息过程中,校验通过 input
框的 onChange
事件触发,所以我们需要用到 simulate
来触发事件。其中一个用例如下
const accountInput = wrapper.find('.account').find('input');
const accountTitle = wrapper.find('.account .name').find('span');
it('输入不合法账号', () => {
const event = {
target: {
value: 'abc123'
}
}
accountInput.simulate('change', event);
expect(accountTitle.text()).toBe('账户输入错误,请重新输入');
})
模拟输入来一个不合法的账号‘abc123’,验证失败,显示失败信息。
在4,5,6三个用例中,需要获取登录按钮 Button
组件的可点击状态,由于 enzyme
无法获取 css
状态,此时可以使用API中的 prop(key)
来获取组件的props状态,从而判断组件的可点击状态。其中一个用例如下
it('输入正确账号,密码小于6位,指定状态', () => {
wrapper.setState({
account: '18888888888',
password: '12345',
errorAccount: false
});
// 此处需重新获取btn对象,否则会导致用例失败
const submitBtn = wrapper.find('.btn-box').find('Button');
expect(submitBtn.props().disabled).toBe(true);
})
此处通过直接设置 state
的值来更改Button的状态。需要注意的是,为来减少重复定义,许多Dom对象的获取都在 describe
组下做了统一的定义,但在执行 expect
获取按钮状态是,需要重新查找,来获取最新但状态。除了直接指定 state
状态之外,还可以通过输入框输入,change事件触发但方式来完成用例,如下
it('输入正确账号,密码小于6位,通过change触发', () => {
const accountEvent = {
target: {
value: '18888888888'
}
};
const pwdEvent = {
target: {
value: '12345'
}
}
accountInput.simulate('change', accountEvent);
passwordInput.simulate('change', pwdEvent);
const submitBtn = wrapper.find('.btn-box').find('Button');
expect(submitBtn.prop('disabled')).toBe(true);
7、8两个用例使用但方法与上面相同,不再赘述。
所有用例编写完成之后,执行 npm run test
可以看到所有用例都通过测试。
测试覆盖率
在 package.json
文件的 test
命令修改为
test: "jest --coverage"
执行 npm run test
即可在用例执行信息后显示用例的覆盖率报告。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Agile Web Development with Rails, Third Edition
Sam Ruby、Dave Thomas、David Heinemeier Hansson / Pragmatic Bookshelf / 2009-03-17 / USD 43.95
Rails just keeps on changing. Rails 2, released in 2008, brings hundreds of improvements, including new support for RESTful applications, new generator options, and so on. And, as importantly, we’ve a......一起来看看 《Agile Web Development with Rails, Third Edition》 这本书的介绍吧!