前端自动化测试详解(下)

阅读数:547 2019 年 9 月 26 日 23:45

前端自动化测试详解(下)

5.4 测试方案代码

下面开始梳理完整的自动化测试方案,整体目录结构如下:

前端自动化测试详解(下)

自动化测试方案项目结构
5.4.1 单元测试

(1)对如下方法进行单元测试

复制代码
1// /src/client/common/js/testUtil.js
2export const sum = (a, b) => {
3 return a + b
4}

编写好测试用例

复制代码
1import { sum } from '../../src/client/common/js/testUtil.js'
2const { expect } = require('chai')
3
4describe('单元测试: sum (a, b)', function () {
5 it('1+1 应该等于 2', function () {
6 expect(sum(1, 1)).to.be.equal(2)
7 })
8})
9// skip 可以指定跳过某个分组
10describe.skip('单元测试:金额按千分位逗号分隔的方法 formatMoney (s, type)', function () {...})

然后使用 mocha 执行测试用例,输出结果如下

前端自动化测试详解(下)

单元测试 - 公共方法
可以看到两个测试分组有一个测试通过,一个被我们主动跳过。使用 mocha 执行测试用例时,因为我们指定了测试报告格式 --reporter 参数为 mochawesome,测试报告会被输出为如下的 html 格式

前端自动化测试详解(下)

单元测试报告
为了分析当前测试用例对源代码的覆盖情况,我们使用 Istanbul 生成测试覆盖率报告

前端自动化测试详解(下)

单元测试代码覆盖率报告

代码覆盖率有四个测量维度:

语句覆盖率(statement coverage):是否每个语句都执行了

分支覆盖率(branch coverage):是否每个 if 代码块都执行了

函数覆盖率(function coverage):是否每个函数都调用了

行覆盖率(line coverage):是否每一行都执行了

分别对应上图的 Statements、Branches、Functions、Lines,点击左侧链接可以查看源码测试详情,绿色部分表示已被测试覆盖

前端自动化测试详解(下)

代码覆盖详情
关于测试覆盖率,需要强调的是,我们不应该把测试覆盖率的高低作为检验项目质量的标准,只能作为参考。代码覆盖率真正的意义在于帮助开发者找到代码设计的问题,帮助我们发现为什么有的代码没有被测试覆盖到,是代码设计有问题,还是加入了无用代码,它可以指导我们在代码设计中做更好的抽象,写可测试的代码。

(2)React 组件测试

现在有如下的 React 组件

复制代码
1// /src/client/components/Empty/index.jsx'
2import React, { Component } from 'react'
3import { Icon } from 'antd'
4
5const Empty = (props) => {
6 const placeholder = props.placeholder
7
8 return (
9 <div>
10 <Icon type='meh-o' />
11 <span>{placeholder || '数据为空'}</span>
12 </div>
13 )
14}
15
16module.exports = Empty
17

编写测试用例对它进行测试

复制代码
1import React from 'react'
2import { expect } from 'chai'
3import Enzyme, { mount, render, shallow } from 'enzyme'
4import Adapter from 'enzyme-adapter-react-15.4' // 根据 React 的版本安装适配器
5import Empty from '../../src/client/components/Empty/index.jsx'
6import { spy } from 'sinon' // 对原有的函数进行封装并进行监听
7
8Enzyme.configure({ adapter: new Adapter() }) // 使用 Enzyme 先适配 React 对应的版本
9
10describe('测试 React 组件: <Empty />', () => {
11 it('不传入属性时,组件中 span 的文本为 " 数据为空 "', () => {
12 const wrapper = render(<Empty />)
13 expect(wrapper.find('span').text()).to.equal('数据为空')
14 })
15
16 it('传入属性 " 我是占位文本 " 时,组件中 span 的文本为 " 我是占位文本 "', () => {
17 const wrapper = render(<Empty placeholder='我是占位文本' />)
18 expect(wrapper.find('span').text()).to.equal('我是占位文本')
19 })
20})

使用 mocha 执行测试用例会生成如下测试报告,测试通过

前端自动化测试详解(下)

React 组件测试报告
测试覆盖率报告如下

前端自动化测试详解(下)

React 组件测试覆盖率
!
React 组件代码覆盖详情
5.4.2 接口测试

编写测试用例,使用 supertest 实施接口测试

复制代码
1const request = require('supertest')
2const { expect } = require('chai')
3const BASE_URL = 'http://127.0.0.1:1990'
4
5describe('接口测试:商户登录测试用例', function () {
6 it('登录接口 /api/user/login', function (done) {
7 request(BASE_URL)
8 .post('/api/user/login')
9 .set('Content-Type', 'application/json') // set header 内容
10 .send({ // send body 内容
11 user_code: 666666,
12 password: 666666
13 })
14 .expect(200) // 断言希望得到返回 http 状态码
15 .end(function (err, res) {
16 // console.info(res.body) // 返回结果
17 expect(res.body).to.be.an('object')
18 expect(res.body.data.user_name).to.equal('商户 AAAAA')
19 done()
20 })
21 })
22})

执行接口测试用例生成如下测试报告

前端自动化测试详解(下)

接口测试报告

前端自动化测试详解(下)

接口测试报告
5.4.3 e2e 测试

编写 e2e 测试用例,使用 selenium-webdriver 驱动浏览器进行功能测试

复制代码
1const { expect } = require('chai')
2const { Builder, By, Key, until } = require('selenium-webdriver')
3const chromeDriver = require('selenium-webdriver/chrome')
4const assert = require('assert')
5
6describe('e2e 测试:商户系统端到端测试用例', () => {
7 let driver
8 before(function () {
9 // 在本区块的所有测试用例之前执行
10 driver = new Builder()
11 .forBrowser('chrome')
12 // 设置无界面测试
13 // .setChromeOptions(new chromeDriver.Options().addArguments(['headless']))
14 .build()
15 })
16
17 describe.skip('登录相关传统用例 - 跳过', function () {...})
18
19 describe('登录商户系统', function () {
20 this.timeout(50000)
21 it('登录跳转', async () => {
22 await driver.get('http://dev.company.home.ke.com:1990/login') // 打开商户登录页面
23 await driver.findElement(By.xpath('//*[@id="root"]/div/div[2]/div/ul/li[1]/input')).sendKeys(666666) // 输入用户名
24 await driver.findElement(By.xpath('//*[@id="root"]/div/div[2]/div/ul/li[2]/input')).sendKeys(666666) // 输入密码
25 await driver.findElement(By.xpath('//*[@id="root"]/div/div[2]/div/div/button')).click() // 点击登录按钮
26 const currentTitle = await driver.getTitle()
27 await driver.sleep(2000)
28 expect(currentTitle).to.equal('商户管理系统')
29 })
30 })
31
32 after(() => {
33 // 在本区块的所有测试用例之后执行
34 driver.quit()
35 })
36})

使用 mocha 执行 e2e 测试用例生成如下测试报告

前端自动化测试详解(下)

e2e 测试报告
下图是 selenium-webdriver 驱动 chrome 浏览器自动运行, 进行功能测试

前端自动化测试详解(下)

e2e 测试效果

前端自动化测试详解(下)

驱动浏览器执行测试任务
5.4.4 基准测试

假设当前需要测试正则表达式的 test 方法和字符串的 indexOf 方法的性能,我们通常会采用如下方法进行测试:让两个方法分别执行 1000 次,比较哪个耗时长。

复制代码
1// 判断某个字符串中是否存在特定字符,比较 reg.test 和 str.indexOf 性能
2const testPerf = (count) => {
3 var now = new Date() - 1
4 var i = count
5 while (i--) {
6 /o/.test('Hello World!')
7 }
8 console.log(`test 方法执行 ${count}次用时`, new Date() - 1 - now)
9}
10
11const indexOfPerf = (count) => {
12 var now = new Date() - 1
13 var i = count
14 while (i--) {
15 'Hello World!'.indexOf('o') > -1
16 }
17 console.log(`indexOf 方法执行 ${count}次用时`, new Date() - 1 - now)
18}
19
20testPerf(1000)
21indexOfPerf(1000)

测试结果如下,因为代码执行较快,两个方法执行 1000 次的时间都为零, 无法准确判断代码执行效率

前端自动化测试详解(下)

方法性能对比
科学的统计方法是需要多次执行,对大量的执行结果进行采样,我们可以使用工具帮我们完成这件事,如下使用 benchmark 进行测试 ``` 1// 判断某个字符串中是否存在特定字符,比较 reg.test 和 str.indexOf 性能 2const Benchmark = require('benchmark') 3const suite = new Benchmark.Suite() 4 5// add test 6suite.add('正则表达式 test 方法', function () { 7 /o/.test('Hello World!') 8}) 9 .add('字符串 indexOf 方法', function () { 10 'Hello World!'.indexOf('o') > -1 11 }) 12 // add listeners 13 .on('cycle', function (event) { 14 console.log(String(event.target)) 15 }) 16 .on('complete', function () { 17 console.log('Fastest is ' + this.filter('fastest').map('name')) 18 }) 19 // run async 20 .run({ 'async': true }) ``` 执行测试代码,结果如下,indexOf 每秒执行的次数比 test 每秒执行的次数超出了一个数量级,所以 indexOf 性能更好

前端自动化测试详解(下)

基准测试结果

6 总结

梳理完单元测试、接口测试、功能测试、基准测试的具体实施方案后,结合自动化测试的特点我们可以得出以下结论:

前端要不要进行自动化测试,需要根据具体的项目特点进行判断,对于满足以下条件的代码可以进行自动化测试:

  • 核心功能模块、函数
  • 短期不会发生变化的 UI 组件
  • 提供外部调用的接口
  • 对方法性能进行基准测试

最后,要强调一点,我们的目标是保证代码健壮、可维护,提高开发效率,自动化测试只是一种手段。

作者介绍:
扣丁(企业代号名),目前负责贝壳找房装修平台 B 端业务研发工作。

本文转载自公众号贝壳产品技术(ID:gh_9afeb423f390)。

原文链接:

https://mp.weixin.qq.com/s/pwSzGhRM_25GTjKd2aRt1Q

评论

发布