【实战】一、Jest 前端自动化测试框架根本入门(三) —— 前端要学的测试 ...

打印 上一主题 下一主题

主题 842|帖子 842|积分 2526


   学习内容来源:Jest入门到TDD/BDD双实战_前端要学的测试课
  
相对原教程,我在学习开始时(2023.08)采用的是当前最新版本:
项版本@babel/core^7.16.0@pmmmwh/react-refresh-webpack-plugin^0.5.3@svgr/webpack^5.5.0@testing-library/jest-dom^5.17.0@testing-library/react^13.4.0@testing-library/user-event^13.5.0babel-jest^27.4.2babel-loader^8.2.3babel-plugin-named-asset-import^0.3.8babel-preset-react-app^10.0.1bfj^7.0.2browserslist^4.18.1camelcase^6.2.1case-sensitive-paths-webpack-plugin^2.4.0css-loader^6.5.1css-minimizer-webpack-plugin^3.2.0dotenv^10.0.0dotenv-expand^5.1.0eslint^8.3.0eslint-config-react-app^7.0.1eslint-webpack-plugin^3.1.1file-loader^6.2.0fs-extra^10.0.0html-webpack-plugin^5.5.0identity-obj-proxy^3.0.0jest^27.4.3jest-enzyme^7.1.2jest-resolve^27.4.2jest-watch-typeahead^1.0.0mini-css-extract-plugin^2.4.5postcss^8.4.4postcss-flexbugs-fixes^5.0.2postcss-loader^6.2.1postcss-normalize^10.0.1postcss-preset-env^7.0.1prompts^2.4.2react^18.2.0react-app-polyfill^3.0.0react-dev-utils^12.0.1react-dom^18.2.0react-refresh^0.11.0resolve^1.20.0resolve-url-loader^4.0.0sass-loader^12.3.0semver^7.3.5source-map-loader^3.0.0style-loader^3.3.1tailwindcss^3.0.2terser-webpack-plugin^5.2.5web-vitals^2.1.4webpack^5.64.4webpack-dev-server^4.6.0webpack-manifest-plugin^4.0.2workbox-webpack-plugin^6.4.1" 具体配置、操作和内容会有差异,“坑”也会有所差异。。。

一、Jest 前端自动化测试框架根本入门

   

  • 一、Jest 前端自动化测试框架根本入门(一)
  
  

  • 一、Jest 前端自动化测试框架根本入门(二)
  7.异步代码的测试方法

安装 axios
  1. npm i axios@0.19.0 -S
复制代码
新建 fetchData.js:
  1. import axios from 'axios'
  2. export const fetchData = (fn) => {
  3.   axios.get('http://www.dell-lee.com/react/api/demo.json').then(res => fn(res.data))
  4. }
复制代码
新建单元测试文件 fetchData.test.js:
  1. import fetchData from './fetchData'
  2. // 回调类型异步函数的测试
  3. test('fetchData 返回结果为 { success: true }', (done) => {
  4.   fetchData((data) => {
  5.     expect(data).toEqual({
  6.       success: true
  7.     })
  8.     // 只有当 done 函数被执行到才认为是测试用例执行结束
  9.     done();
  10.   })
  11. })
复制代码
  不使用 done 的话,测试用例执行到 fetchData 之后直接就返回 pass
  还有一种环境,将 Promise 对象直接返回出来:修改 fetchData.js:
  1. import axios from 'axios'
  2. export const fetchData = () => {
  3.   return axios.get('http://www.dell-lee.com/react/api/demo.json')
  4. }
复制代码
相应修改单元测试文件 fetchData.test.js:
  1. import fetchData from './fetchData'
  2. test('fetchData 返回结果为 Promise: { success: true }', () => {
  3.   return fetchData().then((res) => {
  4.     expect(res.data).toEqual({
  5.       success: true
  6.     })
  7.   })
  8. })
复制代码
如果想要单独测试 404,可以修改为如下
  1. import fetchData from './fetchData'
  2. test('fetchData 返回结果为 404', () => {
  3. expect.assertions(1) // 下面的 expect 至少执行一个
  4.   return fetchData().catch((e) => {
  5.     expect(e.toString().indexOf('404') > -1).toBe(true)
  6.   })
  7. })
复制代码
  如果不使用 expect.assertions ,当测试 接口访问成功,没走 catch 时,相当于啥也没有执行,也会通过,加上后如果接口访问成功会报错:Expected one assertion to be called but received zero assertion calls.
  还有可以使用 expect 自带的函数辨认结果:
  1. test('fetchData 返回结果为 Promise: { success: true }', () => {
  2.   return expect(fetchData()).resolves.toMatchObject({
  3.     data: {
  4.       success: true
  5.     }
  6.   })
  7. })
复制代码
  1. test('fetchData 返回结果为 404', () => {
  2.   return expect(fetchData()).rejects.toThrow()
  3. })
复制代码
除了使用 return 还可以使用 async…await 的语法:
  1. test('fetchData 返回结果为 Promise: { success: true }', async () => {
  2.   await expect(fetchData()).resolves.toMatchObject({
  3.     data: {
  4.       success: true
  5.     }
  6.   })
  7. })
复制代码
  1. test('fetchData 返回结果为 404', async () => {
  2.   await expect(fetchData()).rejects.toThrow()
  3. })
复制代码
还可以使用 async…await 先拿到相应结果,再判断:
  1. test('fetchData 返回结果为 Promise: { success: true }', async () => {
  2.   const res = await fetchData()
  3.   expect(res.data).toEqual({
  4.       success: true
  5.   })
  6. })
复制代码
  1. test('fetchData 返回结果为 404', async () => {
  2.   expect.assertions(1) // 下面的 expect 至少执行一个
  3.   try {
  4.     await fetchData()
  5.   } catch (e) {
  6.     expect(e.toString()).toEqual('Error: Request failed with status code 404.')
  7.   }
  8. })
复制代码
8.Jest 中的钩子函数

Jest 中的钩子函数指的是在 Jest 执行过程中到某一特定时刻被自动调用的函数,类似 Vue/React 中的生命周期函数
新建 Counter.js
  1. export default class Counter {
  2.   constructor() {
  3.     this.number = 0
  4.   }
  5.   addOne() {
  6.     this.number += 1
  7.   }
  8.   minusOne() {
  9.     this.number -= 1
  10.   }
  11. }
复制代码
新建 Counter.test.js
  1. import Counter from "./Counter";
  2. describe('测试 Counter', () => {
  3.   const counter = new Counter();
  4.   
  5.   test('测试 addOne 方法', () => {
  6.     counter.addOne()
  7.     expect(counter.number).toBe(1)
  8.   })
  9.   
  10.   test('测试 minusOne 方法', () => {
  11.     counter.minusOne()
  12.     expect(counter.number).toBe(0)
  13.   })
  14. })
复制代码
运行测试用例,直接通过,但是两个测试用例共用了一个实例 counter,相互之间有影响,这显然是不可以的,可以引入 Jest 的 钩子函数来做预处理
修改 Counter.test.js
  1. import Counter from "./Counter";
  2. describe('测试 Counter', () => {
  3.   let counter = null
  4.   beforeAll(() => {
  5.     console.log('beforeAll')
  6.   })
  7.   beforeEach(() => {
  8.     console.log('beforeEach')
  9.     counter = new Counter();
  10.   })
  11.   afterEach(() => {
  12.     console.log('afterEach')
  13.     // counter = null
  14.   })
  15.   afterAll(() => {
  16.     console.log('afterAll')
  17.   })
  18.   
  19.   test('测试 addOne 方法', () => {
  20.     console.log('测试 addOne ')
  21.     counter.addOne()
  22.     expect(counter.number).toBe(1)
  23.   })
  24.   
  25.   test('测试 minusOne 方法', () => {
  26.     console.log('测试 minusOne ')
  27.     counter.minusOne()
  28.     expect(counter.number).toBe(-1)
  29.   })
  30. })
复制代码
这样就不会相互之间产生影响了
编辑 Counter.js 新增两个方法
  1. export default class Counter {
  2.   constructor() {
  3.     this.number = 0
  4.   }
  5.   addOne() {
  6.     this.number += 1
  7.   }
  8.   addTwo() {
  9.     this.number += 2
  10.   }
  11.   minusOne() {
  12.     this.number -= 1
  13.   }
  14.   minusTwo() {
  15.     this.number -= 2
  16.   }
  17. }
复制代码
这时候测试文件怎么写呢?很显然功能有分类,可以使用 describe
编辑 Counter.test.js
  1. import Counter from "./Counter";
  2. describe('测试 Counter', () => {
  3.   let counter = null
  4.   beforeAll(() => {
  5.     console.log('beforeAll')
  6.   })
  7.   beforeEach(() => {
  8.     console.log('beforeEach')
  9.     counter = new Counter();
  10.   })
  11.   afterEach(() => {
  12.     console.log('afterEach')
  13.     // counter = null
  14.   })
  15.   afterAll(() => {
  16.     console.log('afterAll')
  17.   })
  18.   
  19.   describe('测试“增加”相关的方法', () => {
  20.     test('测试 addOne 方法', () => {
  21.       console.log('测试 addOne ')
  22.       counter.addOne()
  23.       expect(counter.number).toBe(1)
  24.     })
  25.     test('测试 addTwo 方法', () => {
  26.       console.log('测试 addTwo ')
  27.       counter.addTwo()
  28.       expect(counter.number).toBe(2)
  29.     })
  30.   })
  31.   
  32.   
  33.   describe('测试“减少”相关的方法', () => {
  34.     test('测试 minusOne 方法', () => {
  35.       console.log('测试 minusOne ')
  36.       counter.minusOne()
  37.       expect(counter.number).toBe(-1)
  38.     })
  39.     test('测试 minusTwo 方法', () => {
  40.       console.log('测试 minusTwo ')
  41.       counter.minusTwo()
  42.       expect(counter.number).toBe(-2)
  43.     })
  44.   })
  45. })
复制代码
测试日志如下:
  1. 测试 Counter
  2.     测试“增加”相关的方法
  3.       √ 测试 addOne 方法 (6ms)
  4.       √ 测试 addTwo 方法 (4ms)
  5.     测试“减少”相关的方法
  6.       √ 测试 minusOne 方法 (4ms)
  7.       √ 测试 minusTwo 方法 (4ms)
  8.   console.log Counter.test.js:8
  9.     beforeAll
  10.   console.log Counter.test.js:12
  11.     beforeEach
  12.   console.log Counter.test.js:27
  13.     测试 addOne
  14.   console.log Counter.test.js:17
  15.     afterEach
  16.   console.log Counter.test.js:12
  17.     beforeEach
  18.   console.log Counter.test.js:32
  19.     测试 addTwo
  20.   console.log Counter.test.js:17
  21.     afterEach
  22.   console.log Counter.test.js:12
  23.     beforeEach
  24.   console.log Counter.test.js:41
  25.     测试 minusOne
  26.   console.log Counter.test.js:17
  27.     afterEach
  28.   console.log Counter.test.js:12
  29.     beforeEach
  30.   console.log Counter.test.js:46
  31.     测试 minusTwo
  32.   console.log Counter.test.js:17
  33.     afterEach
  34.   console.log Counter.test.js:22
  35.     afterAll
  36. Test Suites: 1 passed, 1 total
  37. Tests:       4 passed, 4 total
  38. Snapshots:   0 total
  39. Time:        4.411s
复制代码
9.钩子函数的作用域

每一个 describe 都可以有自己的 beforeAll、afterAll、beforeEach、afterEach,执行顺序是从外往内。
外部的钩子函数可以对当前 describe 全部的测试用例起作用,而内部的只对内部的测试用例起作用,这就是钩子函数的作用域。
可以自行编写尝试,这里就不再赘述了。
还有一个单元测试小技巧,test 使用 only 修饰符可以让单元测试只运行这一个测试用例:
  1. test.only('', () => {})
复制代码
  留意,代码执行顺序中,最先执行的是不包罗在任何测试用例和钩子函数中的语句(直接暴露在各个 describe 内部最外层的语句),且只执行一次,后续才是测试用例和钩子函数的执行。
  
本文仅作记录, 实战要点待后续专文总结,敬请期待。。。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

冬雨财经

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表