测试与自动化
软件测试和自动化测试介绍
了解什么是软件测试,以及自动化方式的测试
什么是软件测试?
定义:
在规定的条件下对程序进行操作,以发现程序错误,衡量软件质量,并对其是否能满足设计要求进行评估的过程。
目的:
促进目标鉴定软件的正确性、完整性、安全性和质量。
本质:
其实是对软件的 ”预期输出“ 与 ”实际输出“ 之间的比较过程
常用测试方法:
- 黑盒测试:主要以用户的视角来测试程序的功能,所以也称功能测试
- 白盒测试:主要测试程序的代码逻辑,所以也称代码测试
什么是自动化测试?
早先的软件测试工作大都由人来手工完成,其过程极度重复、枯燥、易出错。
而自动化测试则利用程序来模拟人工操作,有效规避了以上问题。
自动化测试的分类:
- 单元测试:属于一种白盒测试,即编写代码来对项目中的小部件代码进行测试(比如一个函数)
- 集成测试:属于一种白盒测试,即在单元测试基础上,将模块按设计要求组装为子系统或完整系统进行测试
- e2e测试:属于一种黑盒测试,即编写自动化脚本模拟用户操作,检测界面间通信、数据传递等是否如预期
- 快照测试:属于一种黑盒测试,即事先准备好理想中的参考文件(参考照片),然后再去访问程序并记录当前界面内容(临场拍照),最后比对两者内容是否一致
前端自动化测试框架
了解目前流行的几个用于前端的自动化测试框架
完整的自动化测试框架应包含以下 3 个部分:
- 断言库(Assertion Library):用于比对 ”预期输出“ 和 ”实际输出“,并抛出错误
- 模拟库(Mock Library):用于模拟数据对象、网络接口等
- 测试运行器(Test Runner):用于运行测试代码
一、常用前端单元测试框架:
- Jest(完整测试框架)- 一个由 Facebook 开源的测试框架,比较新而且目前也比较火- 功能全面- 零配置
- Mocha(核心测试框架)- 一个比较成熟的测试框架,社区很大- 功能单一但非常灵活,能轻易与其他库结合,比如:Chai(断言库)、Karma(测试运行器)- 对异步代码的测试支持的非常好
二、常用的e2e测试框架:
- Cypress.io
- Puppeteer
使用Jest编写单元测试
使用 Jest 框架来编写单元测试的基本用法
核心内容:
- jest 的基本用法
Jest会自动识别和执行项目中所有以
.test.js
为后缀的测试代码文件。
具体步骤:
- 新建项目并安装 jest
npm i jest --save-dev
- 编写一些功能代码(先使用 CommonJS 模块,因为用 ESM 需要借助 Babel,后面会举例)
src/util.js
functiontoUpperCase(str){return str ? str.toUpperCase():""}
module.exports ={
toUpperCase
}
- 编写用于测试以上代码的 jest 测试代码
jest 提供的常用测试函数:
test()
:创建测试用例,代表一个要测试的场景expect()
:创建匹配器,并利用.toBe()
、.toEqual()
等方法进行数据比对
src/util.test.js
// 导入要测试的模块const{ toUpperCase }=require('./util')// 测试用例1:传入参数 'hello',返回 'HELLO'test('hello to HELLO',()=>{expect(toUpperCase('hello')).toBe('HELLO')})// 测试用例2:传入参数 null,返回 ''test('null to whitespace',()=>{expect(toUpperCase(null)).toBe('')})
- 执行测试
npx jest
运行结果:
如果目标代码使用了 ESM 模块化,那测试代码也需用 ESM。这时需要安装配置 Babel 进行支持:
- 安装 babel
npm i babel-jest @babel/core @babel/preset-env --save-dev
- 创建
babel.config.js
module.exports ={presets:[['@babel/preset-env',{targets:{node:'current'}}]],};
- 在测试代码中使用
import
导入目标测试代码
import{ toUpperCase }from'./util'
统计测试覆盖率
了解测试覆盖率的含义和功能
测试覆盖率,也叫代码覆盖率,指的是被测试的目标代码中至少被执行了一次的条目数占所有条目数的百分比。
它是衡量测试的充分性和完整性的重要指标。
覆盖率根据统计条目的类型,细分为:
语句覆盖率
:以代码语句为最小单位路径覆盖率
:以逻辑路径为最小单位函数覆盖率
:以函数为最小单位代码行覆盖率
:以代码行为最小单位
统计代码覆盖率的目的:
- 找出遗漏的测试场景
- 找出没用到的代码
常用工具
- Jest - 自带了覆盖率统计工具
- Karma - 借助第三方库 Istanbul
具体步骤
- 在上一章节代码中,执行以下命令生成覆盖率报告
npx jest --coverage
运行结果:
在这里插入图片描述
另外会生成一个包含 html 格式覆盖率报告的
coverage
目录。
使用Jest测试异步代码
测试包含有如网络请求、定时器等异步行为的目标代码
核心内容:
- jest 处理异步代码的方式
方式一:回调风格
通过
test()
的回调函数参数 done (它也是个函数,调用它即可告知完成异步任务)
test('some desc',done=>{someAsyncTask(data=>{try{expect(data).toBe('....')done()}catch(e){done(e)}})})
方式二:Promise/async + await 风格
通过在
test()
的回调函数中返回一个 promise 对象
test('some desc',()=>{returnsomeAsyncTask().then(data=>{expect(data).toBe('...')})})
或直接用
async/await
test('some desc',async()=>{const data =awaitsomeAsyncTask()expect(data).toBe('...')})
具体步骤:
- 在上一章节代码基础上,安装 axios 包,并在
src/util.js
中编写一个网络接口调用函数
npm i axios --save
src/util.js
import axios from'axios'exportfunctiongetRemoteData(){const url ='http://www.liulongbin.top:3006/api/getbooks'return axios.get(url).then(res=> res.data)}
- 在
src/util.test.js
测试代码中添加新的测试用例:
import{ toUpperCase, getRemoteData }from'./util'// 测试用例3:获取异步数据test('get remote data',async()=>{// 测试返回 promise 的异步代码,必须要返回 promise 对象// 这样才能让测试正确结束const data =awaitgetRemoteData()expect(data.status).toBe(200)})
使用Cypress进行e2e测试
安装和使用 Cypress 进行端到端测试
核心内容:
- 安装和启动 Cypress
- 编写和运行 Cypress 测试代码
具体步骤:
- 安装 Cypress
npm i cypress --save-dev
- 打开 Cypress
npx cypress open
Cypress 会搜索到用户电脑上的所有浏览器,供测试时选用:
创建e2e测试
测试文件名请按xxx.spec.js
这种命名规则。
编写测试代码
e2e测试的本质其实就是模拟用户操作,即用户是如何使用网页界面的。所以 e2e 测试代码就是在利用各种 API 操作网页而已。
Cypress 使用了 Mocha + Chai,因此编写测试代码时用的是来自这两个库的函数,如:
describe
、
it
、
expect
等。
/// <reference types="cypress" />describe('测试百度搜索功能',()=>{// 每个测试用例都会执行的前置行为beforeEach(()=>{// 打开百度首页
cy.visit('https://www.baidu.com')})// 一个测试用例it('应该得到搜索结果',()=>{// 获取百度首页的关键字输入框,并输入关键字
cy.get('#kw').type('前端e2e测试')// 获取百度首页的搜索按钮,并点击
cy.get('#su').click()// 对比结果
cy.get('.nums_text').should('have.text','百度为您找到相关结果约3,190,000个')})})
- 点击用例,运行测试
测试 Vue 项目
介绍针对 Vue 开发的应用代码进行自动化测试的工具
核心内容:
- 针对 Vue 代码的测试工具介绍
- 在 Vue 代码中添加测试工具,并编写测试案例
Vue的代码测试涉会及到以下三类:
- 单元测试(测试函数)- 可使用 Jest 或 Mocha,官方提供了相关插件,可查看官方文档
- 组件测试(测试Vue组件)- 官方推荐使用 Vue Test Utils 或它的进一步封装库 Vue Testing Library
- e2e测试(测试界面)- 可使用专为 Vue 封装的 Cypress
具体步骤:
一、测试 Vue 组件
- 在现有的 Vue CLI 项目中,通过 vue-cli 提供的命令添加 Vue Testing Library
# 单元测试
vue add @vue/unit-jest
# 端到端测试
vue add @vue/e2e-cypress
执行后项目中会新增测试专用目录
tests
:
- 编写一个新组件
Counter.vue
,并在App.vue
中调用
Counter.vue
:
<template><div><h1 class="title">
当前计数:
<span class="count">{{ count }}</span></h1><div><button class="btn decrease" @click="decreaseHandler">减少</button><button class="btn increase" @click="increaseHandler">增加</button></div></div></template><script>exportdefault{props:{init:{type: Number,default:0}},data(){return{count:this.init
}},methods:{increaseHandler(){this.count +=1},decreaseHandler(){this.count -=1}}}</script><style>.count {color: red;}</style>
App.vue
中的调用:
<Counter :init="10"/>
- 针对
Counter.vue
组件,编写以下几个单元测试
tests/unit/count.spec.js
import Counter from'@/components/Counter.vue'import{ mount }from'@vue/test-utils'describe('Counter.vue',()=>{it('不传 init 属性时显示的初始计数是 0',()=>{// 渲染组件const wrapper =mount(Counter)// 获取组件内的数据expect(wrapper.vm.count).toBe(0)})it('传入 init 属性值为 10 时显示的初始计数是 10',()=>{const wrapper =mount(Counter,{// 为组件传入属性propsData:{init:10}})expect(wrapper.vm.count).toBe(10)})it('点击 3 下增加按钮及 1 下减少按钮,当前计数增加 2',()=>{const wrapper =mount(Counter)// 获取组件内的元素const btnIncrease = wrapper.find('.increase')const btnDecrease = wrapper.find('.decrease')// 模拟用户点击
btnIncrease.trigger('click')
btnIncrease.trigger('click')
btnIncrease.trigger('click')
btnDecrease.trigger('click')// 比对数据expect(wrapper.vm.count).toBe(2)})})
- 运行单元测试
npm run test:unit
在以上单元测试中进行数据比对时,都从组件的实例(vm 对象)上获取数据来进行比对,但有时我们想测试的是界面是否已渲染成我们期望的内容,这时应该这样写:
it('点击 3 下增加按钮及 1 下减少按钮,当前计数增加 2',async()=>{const wrapper =mount(Counter)// 获取组件内的元素const btnIncrease = wrapper.find('.increase')const btnDecrease = wrapper.find('.decrease')// (修改点1)模拟用户点击(使用 await)await btnIncrease.trigger('click')await btnIncrease.trigger('click')await btnIncrease.trigger('click')await btnDecrease.trigger('click')// (修改点2)获取界面上的内容来进行数据比较expect(wrapper.get('.count').text()).toBe('2')})
说明:此处使用
await
是因为
click
事件是异步的,这样才能在异步行为发生后正确获取重新渲染后的界面内容。
二、e2e 测试
在 vue 中进行 e2e 测试其实和直接使用
Cypress
没有太大差别。
- 通过以下命令启动 Cypress
npm run test:e2e
- 和之前一样,编写和运行 Cypress 测试脚本即可
版权归原作者 不停喝水 所有, 如有侵权,请联系我们删除。