Jest 是 Facebook 发布的一个开源的、基于 Jasmine 框架的 JavaScript 单元测试工具。css
Enzyme 是 React 的测试类库。 Enzyme 提供了一套简洁强大的 API,并经过 jQuery 风格的方式进行DOM 处理,开发体验十分友好。html
首先,使用npm
安装Jestnode
npm install --save-dev jest
在目录下新建一个待测试文件 sort.js
。react
function sort(sortArr) { return sortArr.sort((a, b) => a - b); } module.exports = sort;
此处sort方法未对入参作类型检测jquery
在这里定义了一个数组排序方法,下面来书写其测试用例,在目录下新建一个sort.test.js
文件。webpack
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()
等方法来比较不一样的类型。更多内容...git
打开package.json
,在scripts
中新增es6
test: "jest"
而后运行命令github
npm run test
会看到用例测试经过的信息web
因为咱们的方法没有作入参类型检测,下面经过传入字符串,来测试异常状况。在sort.test.js
中新增一个测试用例用例
test('排序字符串“52431”', () => { expect(sort('52431')).toEqual(12345); })
运行,则会看到测试失败的信息
从测试结果中咱们能够清除的看到,运行来两个测试用例,第一个用例经过来,第二个用例运行是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定义来八个测试用例以下
接下来,新建文件login.test.js
来编写测试用例代码。
因为用例中设计多个交互,因此咱们须要先渲染出组件。Enzyme为咱们提供来三种渲染组件的方法shallow
、render
、mount
。
shallow
方法就是官方的shallow rendering的封装。render
方法将React组件渲染成静态的HTML字符串,而后分析这段HTML代码的结构,返回一个对象。它跟shallow方法很是像,主要的不一样是采用了第三方HTML解析库Cheerio,它返回的是一个Cheerio实例对象。mount
方法用于将React组件加载为真实DOM节点。三种方法中,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);
七、8两个用例使用但方法与上面相同,再也不赘述。
全部用例编写完成以后,执行npm run test
能够看到全部用例都经过测试。
在 package.json
文件的 test
命令修改成
test: "jest --coverage"
执行 npm run test
便可在用例执行信息后显示用例的覆盖率报告。