【实战】一、Jest 前端自动化测试框架基础入门(三) —— 前端要学的测试课 从Jest入门到TDD BDD双实战(三)

06-01 1140阅读

文章目录

    • 一、Jest 前端自动化测试框架基础入门
      • 7.异步代码的测试方法
      • 8.Jest 中的钩子函数
      • 9.钩子函数的作用域

        学习内容来源: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.0
        babel-jest^27.4.2
        babel-loader^8.2.3
        babel-plugin-named-asset-import^0.3.8
        babel-preset-react-app^10.0.1
        bfj^7.0.2
        browserslist^4.18.1
        camelcase^6.2.1
        case-sensitive-paths-webpack-plugin^2.4.0
        css-loader^6.5.1
        css-minimizer-webpack-plugin^3.2.0
        dotenv^10.0.0
        dotenv-expand^5.1.0
        eslint^8.3.0
        eslint-config-react-app^7.0.1
        eslint-webpack-plugin^3.1.1
        file-loader^6.2.0
        fs-extra^10.0.0
        html-webpack-plugin^5.5.0
        identity-obj-proxy^3.0.0
        jest^27.4.3
        jest-enzyme^7.1.2
        jest-resolve^27.4.2
        jest-watch-typeahead^1.0.0
        mini-css-extract-plugin^2.4.5
        postcss^8.4.4
        postcss-flexbugs-fixes^5.0.2
        postcss-loader^6.2.1
        postcss-normalize^10.0.1
        postcss-preset-env^7.0.1
        prompts^2.4.2
        react^18.2.0
        react-app-polyfill^3.0.0
        react-dev-utils^12.0.1
        react-dom^18.2.0
        react-refresh^0.11.0
        resolve^1.20.0
        resolve-url-loader^4.0.0
        sass-loader^12.3.0
        semver^7.3.5
        source-map-loader^3.0.0
        style-loader^3.3.1
        tailwindcss^3.0.2
        terser-webpack-plugin^5.2.5
        web-vitals^2.1.4
        webpack^5.64.4
        webpack-dev-server^4.6.0
        webpack-manifest-plugin^4.0.2
        workbox-webpack-plugin^6.4.1"

        具体配置、操作和内容会有差异,“坑”也会有所不同。。。


        一、Jest 前端自动化测试框架基础入门

        • 一、Jest 前端自动化测试框架基础入门(一)
          • 一、Jest 前端自动化测试框架基础入门(二)

            7.异步代码的测试方法

            安装 axios

            npm i axios@0.19.0 -S
            

            新建 fetchData.js:

            import axios from 'axios'
            export const fetchData = (fn) => {
              axios.get('http://www.dell-lee.com/react/api/demo.json').then(res => fn(res.data))
            }
            

            新建单元测试文件 fetchData.test.js:

            import fetchData from './fetchData'
            // 回调类型异步函数的测试
            test('fetchData 返回结果为 { success: true }', (done) => {
              fetchData((data) => {
                expect(data).toEqual({
                  success: true
                })
                // 只有当 done 函数被执行到才认为是测试用例执行结束
                done();
              })
            })
            

            不使用 done 的话,测试用例执行到 fetchData 之后直接就返回 pass

            还有一种情况,将 Promise 对象直接返回出来:修改 fetchData.js:

            import axios from 'axios'
            export const fetchData = () => {
              return axios.get('http://www.dell-lee.com/react/api/demo.json')
            }
            

            相应修改单元测试文件 fetchData.test.js:

            import fetchData from './fetchData'
            test('fetchData 返回结果为 Promise: { success: true }', () => {
              return fetchData().then((res) => {
                expect(res.data).toEqual({
                  success: true
                })
              })
            })
            

            若是想要单独测试 404,可以修改为如下

            import fetchData from './fetchData'
            test('fetchData 返回结果为 404', () => {
             expect.assertions(1) // 下面的 expect 至少执行一个
              return fetchData().catch((e) => {
                expect(e.toString().indexOf('404') > -1).toBe(true)
              })
            })
            

            若是不使用 expect.assertions ,当测试 接口访问成功,没走 catch 时,相当于啥也没有执行,也会通过,加上后若是接口访问成功会报错:Expected one assertion to be called but received zero assertion calls.

            还有可以使用 expect 自带的函数识别结果:

            test('fetchData 返回结果为 Promise: { success: true }', () => {
              return expect(fetchData()).resolves.toMatchObject({
                data: {
                  success: true
                }
              })
            })
            
            test('fetchData 返回结果为 404', () => {
              return expect(fetchData()).rejects.toThrow()
            })
            

            除了使用 return 还可以使用 async…await 的语法:

            test('fetchData 返回结果为 Promise: { success: true }', async () => {
              await expect(fetchData()).resolves.toMatchObject({
                data: {
                  success: true
                }
              })
            })
            
            test('fetchData 返回结果为 404', async () => {
              await expect(fetchData()).rejects.toThrow()
            })
            

            还可以使用 async…await 先拿到响应结果,再判断:

            test('fetchData 返回结果为 Promise: { success: true }', async () => {
              const res = await fetchData()
              expect(res.data).toEqual({
                  success: true
              })
            })
            
            test('fetchData 返回结果为 404', async () => {
              expect.assertions(1) // 下面的 expect 至少执行一个
              try {
                await fetchData()
              } catch (e) {
                expect(e.toString()).toEqual('Error: Request failed with status code 404.')
              }
            })
            

            8.Jest 中的钩子函数

            Jest 中的钩子函数指的是在 Jest 执行过程中到某一特定时刻被自动调用的函数,类似 Vue/React 中的生命周期函数

            【实战】一、Jest 前端自动化测试框架基础入门(三) —— 前端要学的测试课 从Jest入门到TDD BDD双实战(三)
            (图片来源网络,侵删)

            新建 Counter.js

            export default class Counter {
              constructor() {
                this.number = 0
              }
              addOne() {
                this.number += 1
              }
              minusOne() {
                this.number -= 1
              }
            }
            

            新建 Counter.test.js

            【实战】一、Jest 前端自动化测试框架基础入门(三) —— 前端要学的测试课 从Jest入门到TDD BDD双实战(三)
            (图片来源网络,侵删)
            import Counter from "./Counter";
            describe('测试 Counter', () => {
              const counter = new Counter();
              
              test('测试 addOne 方法', () => {
                counter.addOne()
                expect(counter.number).toBe(1)
              })
              
              test('测试 minusOne 方法', () => {
                counter.minusOne()
                expect(counter.number).toBe(0)
              })
            })
            

            运行测试用例,直接通过,但是两个测试用例共用了一个实例 counter,相互之间有影响,这显然是不可以的,可以引入 Jest 的 钩子函数来做预处理

            修改 Counter.test.js

            【实战】一、Jest 前端自动化测试框架基础入门(三) —— 前端要学的测试课 从Jest入门到TDD BDD双实战(三)
            (图片来源网络,侵删)
            import Counter from "./Counter";
            describe('测试 Counter', () => {
              let counter = null
              beforeAll(() => {
                console.log('beforeAll')
              })
              beforeEach(() => {
                console.log('beforeEach')
                counter = new Counter();
              })
              afterEach(() => {
                console.log('afterEach')
                // counter = null
              })
              afterAll(() => {
                console.log('afterAll')
              })
              
              test('测试 addOne 方法', () => {
                console.log('测试 addOne ')
                counter.addOne()
                expect(counter.number).toBe(1)
              })
              
              test('测试 minusOne 方法', () => {
                console.log('测试 minusOne ')
                counter.minusOne()
                expect(counter.number).toBe(-1)
              })
            })
            

            这样就不会相互之间产生影响了

            编辑 Counter.js 新增两个方法

            export default class Counter {
              constructor() {
                this.number = 0
              }
              addOne() {
                this.number += 1
              }
              addTwo() {
                this.number += 2
              }
              minusOne() {
                this.number -= 1
              }
              minusTwo() {
                this.number -= 2
              }
            }
            

            这时候测试文件怎么写呢?很显然功能有分类,可以使用 describe

            编辑 Counter.test.js

            import Counter from "./Counter";
            describe('测试 Counter', () => {
              let counter = null
              beforeAll(() => {
                console.log('beforeAll')
              })
              beforeEach(() => {
                console.log('beforeEach')
                counter = new Counter();
              })
              afterEach(() => {
                console.log('afterEach')
                // counter = null
              })
              afterAll(() => {
                console.log('afterAll')
              })
              
              describe('测试“增加”相关的方法', () => {
                test('测试 addOne 方法', () => {
                  console.log('测试 addOne ')
                  counter.addOne()
                  expect(counter.number).toBe(1)
                })
                test('测试 addTwo 方法', () => {
                  console.log('测试 addTwo ')
                  counter.addTwo()
                  expect(counter.number).toBe(2)
                })
              })
              
              
              describe('测试“减少”相关的方法', () => {
                test('测试 minusOne 方法', () => {
                  console.log('测试 minusOne ')
                  counter.minusOne()
                  expect(counter.number).toBe(-1)
                })
                test('测试 minusTwo 方法', () => {
                  console.log('测试 minusTwo ')
                  counter.minusTwo()
                  expect(counter.number).toBe(-2)
                })
              })
            })
            

            测试日志如下:

            测试 Counter
                测试“增加”相关的方法
                  √ 测试 addOne 方法 (6ms)
                  √ 测试 addTwo 方法 (4ms)
                测试“减少”相关的方法
                  √ 测试 minusOne 方法 (4ms)
                  √ 测试 minusTwo 方法 (4ms)
              console.log Counter.test.js:8
                beforeAll
              console.log Counter.test.js:12
                beforeEach
              console.log Counter.test.js:27
                测试 addOne
              console.log Counter.test.js:17
                afterEach
              console.log Counter.test.js:12
                beforeEach
              console.log Counter.test.js:32
                测试 addTwo
              console.log Counter.test.js:17
                afterEach
              console.log Counter.test.js:12
                beforeEach
              console.log Counter.test.js:41
                测试 minusOne
              console.log Counter.test.js:17
                afterEach
              console.log Counter.test.js:12
                beforeEach
              console.log Counter.test.js:46
                测试 minusTwo
              console.log Counter.test.js:17
                afterEach
              console.log Counter.test.js:22
                afterAll
            Test Suites: 1 passed, 1 total
            Tests:       4 passed, 4 total
            Snapshots:   0 total
            Time:        4.411s
            

            9.钩子函数的作用域

            每一个 describe 都可以有自己的 beforeAll、afterAll、beforeEach、afterEach,执行顺序是从外往内。

            外部的钩子函数可以对当前 describe 所有的测试用例起作用,而内部的只对内部的测试用例起作用,这就是钩子函数的作用域。

            可以自行编写尝试,这里就不再赘述了。

            还有一个单元测试小技巧,test 使用 only 修饰符可以让单元测试只运行这一个测试用例:

            test.only('', () => {})
            

            注意,代码执行顺序中,最先执行的是不包含在任何测试用例和钩子函数中的语句(直接暴露在各个 describe 内部最外层的语句),且只执行一次,后续才是测试用例和钩子函数的执行。


            本文仅作记录, 实战要点待后续专文总结,敬请期待。。。

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码