• 第五章 Jest进行前端单元测试


    第五章 Jest进行前端单元测试

    单元测试是软件质量的重要保证。在 Github 上挑选一款软件,单元测试覆盖率是评价软件成熟度的一个重要指标。通常成熟可靠的开源产品都有完善的单元测试,并且覆盖率可以达到 80% 以上。

    本章任务

    • 搭建Jest环境
    • 编写有关Jest的函数
    • 引入DOM仿真,完成一个前端页面测试

    task1】搭建 Jest环境

    • 安装依赖
    npm i jest -g
    
    • 1
    • 根目录创建add.js测试文件

    文件名:add.js

    const add = (a, b) => a + b;
    module.exports = add;
    
    • 1
    • 2
    • 编写Jest测试函数

    文件名:src/tests/add.test.js

    const add = require("../../add");
    
    describe("测试Add函数", () => {
      test("add(1,2) === 3", () => {
        expect(add(1, 2)).toBe(3);
      });
      test("add(1,1) === 2", () => {
        expect(add(1, 1)).toBe(2);
      });
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 运行jest测试命令
    jest
    
    • 1

    Jest会自动到项目里面查找所有测试用例文件。

    如果你想不想使用全局的jest:

    pnpm i jest -D
    
    • 1

    测试命令需要加上npx

    npx jest
    
    • 1
    • 控制台查看结果
     PASS  tests/add.test.js
      测试Add函数
        √ add(1,2) === 3 (1 ms)                                                                                                               
        √ add(1,1) === 2                                                                                                                      
                                                                                                                                              
    Test Suites: 1 passed, 1 total                                                                                                            
    Tests:       2 passed, 2 total                                                                                                            
    Snapshots:   0 total
    Time:        0.483 s
    Ran all test suites.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    至此测试环境可用。


    task2】使用Jest的Mock模拟无法执行的函数

    如果被测试的代码,调用了一个网络请求 API ,比如 axios,但是那个网络地址并不存在或者没有联网,这个时候应该如何测试呢?

    • 安装axios开发依赖
    pnpm i axios -D
    
    • 1
    • 根目录创建fetch.js测试文件
    const axios = require('axios')
    exports.getData = () => axios.get('/abc/bcd')
    
    • 1
    • 2

    单元测试是针对开发的最小单位展开的测试,通常是函数。遇到函数调用函数的情况,比如 A 函数调用 B 函数,测试的主体是 A 函数,B 函数应该与测试无关,应该孤立 B 函数来测试 A 函数。

    对于上面的 getData 函数来讲,调用了 axios.get 函数,应该模拟一个 axios.get 函数来替换掉原有的axios.get 函数。模拟的 axios.get 函数不会调用网络请求,只具有根据输入返回相应结果的功能。这个就是Mock函数。

    单元测试的任务是验证 getData 函数的功能是否正确,而不是axios.get 函数或者网络接口是否正确。

    • 编写测试文件

    首先使用 jest.mock创建一个 axios 的 mock 对象。实际上就是创建了一个虚拟的 axios 函数替换原函数。然后通过 mockResolvedValue 定义调用 axios.get 函数的返回值。这个时候再调用getData() 方法的时候 ,函数内部的 axios.get 是虚拟 mock 函数。调用时不会发生真正的网络请求,只会返回预定的结果。

    文件名:src/tests/fetch.test.js

    const { getData } = require("../fetch");
    const axios = require("axios");
    jest.mock("axios");
    it("fetch", async () => {
      // 模拟第一次接收到的数据
      axios.get.mockResolvedValueOnce("123");
      // 模拟每一次接收到的数据
      axios.get.mockResolvedValue("456");
        
      const data1 = await getData();
      const data2 = await getData();
      expect(data1).toBe("123");
      expect(data2).toBe("456");
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 执行测试命令
    jest
    
    • 1
    • 控制台查看结果
     PASS  src/tests/add.test.js
     PASS  src/tests/fetch.test.js
                                                                                                                                              
    Test Suites: 2 passed, 2 total                                                                                                            
    Tests:       3 passed, 3 total
    Snapshots:   0 total
    Time:        0.707 s, estimated 1 s
    Ran all test suites.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    jest.fn()

    jest.fn()是创建Mock函数最简单的方式,如果没有定义函数内部的实现,jest.fn()会返回undefined作为返回值。

    test('测试jest.fn()调用', () => {
      let mockFn = jest.fn();
      let result = mockFn(1, 2, 3);
    
      // 断言mockFn的执行后返回undefined
      expect(result).toBeUndefined();
      // 断言mockFn被调用
      expect(mockFn).toBeCalled();
      // 断言mockFn被调用了一次
      expect(mockFn).toBeCalledTimes(1);
      // 断言mockFn传入的参数为1, 2, 3
      expect(mockFn).toHaveBeenCalledWith(1, 2, 3);
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    task3】测试前端页面

    前端程序和纯 JS 的区别在于运行时不同。前端程序运行于浏览器端,会直接调用 Dom 对象。但是 Node 中并没有 Dom 模型。

    解决的办法有两个 :

    • 将测试用例放到浏览器中运行;
    • dom 仿真模拟一个 dom 对象。

    最佳的选择是后者,因为你的测试程序会放到不同的环境中执行,你不可能要求 CI 服务器中也有浏览器。而且放入浏览器再执行,效率也是一个大问题。

    模拟一个 dom 对象需要用到 dom 仿真,常见的有 jsdomhappydom

    • 安装依赖
    pnpm i jsdom -D
    
    • 1
    • 配置jsdom

    在 jest 中引入 jsdom ,需要编写一个 jsdom-config.js 文件。

    文件名:jsdom-config.js

    // jsdom-config.js
    const jsdom = require('jsdom') // eslint-disable-line
    const { JSDOM } = jsdom
    
    const dom = new JSDOM('', {
      url: 'http://localhost/',
      referrer: 'https://example.com/',
      contentType: 'text/html',
      userAgent: 'Mellblomenator/9000',
      includeNodeLocations: true,
      storageQuota: 10000000,
    })
    global.window = dom.window
    global.document = window.document
    global.navigator = window.navigator
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 编写dom.js被测文件

    函数中创建一个 div 元素。

    文件名:dom.js

    exports.generateDiv = () => {
      const div = document.createElement("div");
      div.className = "c1";
      document.body.appendChild(div);
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 编写dom的测试文件

    在测试程序中,被测试函数创建了一个 div 元素,接着就可以在 dom 仿真中获取 div 元素了。也可以用断言来判断代码功能是否正常。

    文件名:src/tests/dom.test.js

    const { generateDiv } = require('../dom') 
    require('../../jsdom-config')
    describe('Dom测试', () => {
        
        test('测试dom操作', () => {
            generateDiv()
            expect(document.getElementsByClassName('c1').length).toBe(1)
        })
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 执行jest命令
    jest
    
    • 1
    • 控制台查看结果
     PASS  src/tests/fetch.test.js
     PASS  src/tests/add.test.js
     PASS  src/tests/dom.test.js
                                                                                                                                              
    Test Suites: 3 passed, 3 total                                                                                                            
    Tests:       5 passed, 5 total
    Snapshots:   0 total
    Time:        1.647 s
    Ran all test suites.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这个就是 dom 测试。前端常用的 Vue React 程序也都可以使用这样的方法进行测试。

  • 相关阅读:
    linux 利用yum源安装mysql client 5.7
    第十五章总结
    ps2024滤镜插件Portraiture
    OpenCV(十九):模板匹配
    5分钟构建电商API接口服务 | python小知识
    centos下Mysql的安装(离线)
    青少年软件编程C++二级真题(202109)
    FPGA UDP RGMII 千兆以太网(4)ARP ICMP UDP
    postgresql源码学习(33)—— 事务日志⑨ - 从insert记录看日志写入整体流程
    Google Earth Engine(GEE)——单景影像导出到Google 硬盘中
  • 原文地址:https://blog.csdn.net/qq_36362721/article/details/127827738