Jest + Enzyme 前端自动化测试

栏目: 编程工具 · 发布时间: 5年前

内容简介: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 文件,并书写简单的方法用例,执行测试命令,是可以正常执行测试用例的。但是,我们的项目却并不是简单的单个方法但测试,实际项目中会存在这大量的组件依赖,还有 cssimage 等静态资源的处理。所以,还要进行如下配置处理。

首先,我们在 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-loaderurl-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.jsstyleMock.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为我们提供来三种渲染组件的方法 shallowrendermount

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 即可在用例执行信息后显示用例的覆盖率报告。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Spring实战(第4版)

Spring实战(第4版)

Craig Walls 沃尔斯 / 张卫滨 / 人民邮电出版社 / 2016-4-1 / CNY 89.00

《Spring实战(第4版)》是经典的、畅销的Spring学习和实践指南。 第4版针对Spring 4进行了全面更新。全书分为四部分。第1部分介绍Spring框架的核心知识。第二部分在此基础上介绍了如何使用Spring构建Web应用程序。第三部分告别前端,介绍了如何在应用程序的后端使用Spring。第四部分描述了如何使用Spring与其他的应用和服务进行集成。 《Spring实战(第4......一起来看看 《Spring实战(第4版)》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

MD5 加密
MD5 加密

MD5 加密工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具