美文网首页
Jest:优雅的前端单元测试框架

Jest:优雅的前端单元测试框架

作者: 狄仁杰666 | 来源:发表于2022-11-02 16:44 被阅读0次

    前言

    来啦老铁!

    在日常工作中,经常听到前端单元测试(这里只 javascript 或者 node.js),然而由于工作性质,没有机会写这方面的测试代码,好奇的我,决定窥探一下。

    常见的前端单元测试框架有 jest、mocha、jasmine、karma、tape 等,这里头 mocha 笔者是很熟悉的了,几年前在做 UI 自动化测试、后端接口测试的时候,均有用到,它轻量、灵活,但需要自行接入断言、覆盖率统计等插件。而 jest 则是:

    • Jest 是一个功能全面的“零配置”测试框架,既集成了各种工具,且无需配置即可使用。

    这显而易见相比 mocha 会更容易使用!

    其他测试框架 jasmine、karma、tape 等我们根据网友提供的数据:

    测试框架对比
    jest 受欢迎程度遥遥领先,且不说别的,作为学习标的,那是完全没问题的!

    附官方文档:https://jestjs.io/docs/getting-started

    学习路径

    1. 安装 jest;
    2. 编写业务逻辑代码;
    3. 编写单元测试代码;
    4. 运行单元测试;
    5. 测试报告;
    6. 收集代码覆盖率;
    7. 测试用例钩子(hook);
    8. 用例执行控制;
    9. mock;

    1. 安装 jest;

    npm install --save-dev jest
    

    安装完成后,我们以官网的例子,快速进行单元测试学习。

    2. 编写业务逻辑代码;

    创建一个 js 文件,如 sum.js;

    function sum(a, b) {
        return a + b;
    }
    module.exports = sum;
    

    3. 编写单元测试代码;

    创建一个 .test.js 文件,如 sum.test.js;

    const sum = require('./sum');
    
    test('adds 1 + 2 to equal 3', () => {
        expect(sum(1, 2)).toBe(3);
    });
    

    4. 运行单元测试;

    • 我们可以在 package.json 文件内增加一个命令,如:
    "scripts": {
        "test": "jest"
    }
    
    • 接着在命令行执行测试命令:
    npm test
    
    • 测试结果:
    测试结果

    从打印出的信息,可以清楚地看到测试过程和测试结论!而且连断言库都是自带的,不用安装,挺清爽的!

    • 我们可以模拟业务逻辑错误,如修改 sum.js 文件中的代码为:
    function sum(a, b) {
        return a + b + 1;
    }
    module.exports = sum;
    
    • 再次执行单元测试:
    模拟业务逻辑错误

    控制台打印出失败信息,清晰明了!

    5. 测试报告;

    上述执行单元测试的控制台打印,实际上是 jest 提供的 default 报告,如果我们想使用其他报告,改怎么办呢?

    这时候就需要用到 jest config 了!

    我们以 allure 报告为例:

    • 安装 jest-allure 模块;
    npm install --save-dev jest-allure
    
    • 创建 jest config 文件,如 jest.config.js;

    注意:

    如果将 config 文件命名为 jest.config.js|ts|mjs|cjs|json 则 jest 会自动寻找,不需要指定,而如果是其他名字的 config 文件,则需要在执行时使用 --config 参数指定 config 文件。

    • 在 jest.config.js 内输入配置信息;
    const config = {
        reporters: [
            "default",
            "jest-allure"
        ],
        setupFilesAfterEnv: ["jest-allure/dist/setup"],
        testRunner: "jest-jasmine2"
    };
    
    module.exports = config;
    

    注意:

    testRunner: "jest-jasmine2" 这个如果在未填的情况下会报错:

    image.png
    解决办法就是:安装 jest-jasmine2,并声明 testRunner: "jest-jasmine2"
    npm install --save-dev jest-jasmine2
    
    • 再次执行单元测试;
    单元测试 - allure

    我们会看到项目底下多出了 allure-results 文件夹,如何看 allure 报告?这个不是 jest 知识而是 allure 知识,啰嗦几句怎么看吧:

    • 安装 allure 命令行模块 allure-commandline;
    npm install --save-dev allure-commandline
    
    • 浏览器打开 allure 报告:
    npx allure serve
    
    生成报告 allure 报告 1 allure 报告 2
    • 生成 allure 报告 HTML 文件(通常用于 CI 上展示)
    npx allure generate --clean
    

    注意:

    此处未指定报告源的文件夹名和存放的文件夹名,allure 会使用默认文件夹名。

    生成 allure 报告 HTML 文件

    其他报告可参考:

    6. 收集代码覆盖率;

    jest 支持横杠和驼峰结构,覆盖率收集参数如下:

    jest --collect-coverage
    jest --collectCoverage
    

    同样的,我们可以在 package.json 添加个命令,如:

    "test:coverage": "jest --collect-coverage"
    

    则,执行执行单元测试:

    npm run test:coverage
    
    覆盖率

    同时,我们会在项目下看到一个 coverage 文件夹:

    coverage 文件夹

    使用浏览器,打开 coverage/lcov-report 下的 index.html 文件:

    覆盖率 HTML 文件

    在打开的页面上,我们能清楚的看到被测文件、单元测试核心指标们:语句覆盖率(Statements)、分支覆盖率(Branches)、函数覆盖率(Functions)、行覆盖率(Lines),点击被测文件,还能进入覆盖率详情页面:

    覆盖率详情页面

    7. 测试用例钩子(hook);

    如许多测试用例管理框架一样,jest 也有测试用例钩子,如下:

    我们就不多展开了~

    8. 用例执行控制;

    常见的用例执行控制有:

    1. skip:忽略,不进行测试;

    const sum = require('./sum');
    
    test.skip('adds 1 + 2 to equal 3', () => {
        expect(sum(1, 2)).toBe(3);
    });
    
    skip

    2. only:只跑这个测试;

    const sum = require('./sum');
    
    test.only('adds 1 + 2 to equal 3', () => {
        expect(sum(1, 2)).toBe(3);
    });
    
    test('adds 5 + 2 to equal 7', () => {
        expect(sum(5, 2)).toBe(7);
    });
    
    only

    3. 指定测试文件进行测试;

    • 指定单个文件:
    npx jest -- --runTestsByPath ./sum.test.js
    
    • 指定多个文件:
    npx jest -- --runTestsByPath ./sum.test.js ./multiply.test.ts
    

    4. 并行测试与串行测试;

    • 并行测试:jest 默认是在工作进程之间并行运行测试的;

    • 串行测试:

    jest -- --runInBand
    

    5. 控制执行顺序;
    这个有时候挺有用的,虽然应用不应该有这样的顺序要求,但有时候难免会遇到,可以备用一下,例如我们希望按测试文件的字母循序正序或者倒序执行,则:

    • 创建一个自定义 sequencer 文件,例如文件名为:custom-sequencer.js,在文件中输入:
    const Sequencer = require('@jest/test-sequencer').default;
    
    class CustomSequencer extends Sequencer {
        /**
         * Select tests for shard requested via --shard=shardIndex/shardCount
         * Sharding is applied before sorting
         */
        shard(tests, { shardIndex, shardCount }) {
            const shardSize = Math.ceil(tests.length / shardCount);
            const shardStart = shardSize * (shardIndex - 1);
            const shardEnd = shardSize * shardIndex;
    
            return [...tests]
                .sort((a, b) => (a.path > b.path ? 1 : -1))
                .slice(shardStart, shardEnd);
        }
    
        /**
         * Sort test to determine order of execution
         * Sorting is applied after sharding
         */
        sort(tests) {
            // Test structure information
            // https://github.com/facebook/jest/blob/6b8b1404a1d9254e7d5d90a8934087a9c9899dab/packages/jest-runner/src/types.ts#L17-L21
            const copyTests = Array.from(tests);
            return copyTests.sort((testA, testB) => (testA.path > testB.path ? 1 : -1));
        }
    }
    
    module.exports = CustomSequencer;
    
    • 然后在 jest.config.js 内增加一个配置:
    testSequencer: './custom-sequencer.js',
    
    • 最后执行测试,执行时就会按字母循序来了;
    • 如果想要按字母倒序,则只需要将这行稍做修改(大于号改小于号):
    return copyTests.sort((testA, testB) => (testA.path > testB.path ? 1 : -1));
    

    改为:

    return copyTests.sort((testA, testB) => (testA.path < testB.path ? 1 : -1));
    
    • 其他自定义测试执行循序,可自行研究、编写,以后有机会我们可以再研究一下这方面的内容;

    9. mock;

    测试领域,有一个很重要的概念,那就是 mock,特别是单元测试,经常需要用到,例如:

    当我们需要模拟外部(被测对象以外)的某个行为,从而拿到外部行为的结果,我们不需要真的去操作这个外部对象,而是可以使用 mock,模拟这个外部行为,因为我们关注的是我们的代码是否按预期运行!

    举个小例子,假设测 multiply 的时候,第一个数是 sum 以后的值,此时我们不用写 sum 的代码,因为 sum 有 sum 的测试代码去测试,更简便的是,mock 这个 sum 返回,例如:

    const multiply = require('./multiply');
    
    test('multiply 2 * 3 to equal 6', () => {
        const mock = jest.fn();
    
        mock.mockReturnValue(2);
        const sumResult = mock();
    
        expect(multiply(sumResult, 3)).toBe(6);
    });
    
    这样做有助于保证测试的原子性,测试目的单一性原则;

    其他相关的 mock 知识,笔者暂时也未完全看过,官网有十分详细的介绍,请君与我共勉之:mock-function-api

    综上,jest 是一个十分容易上手、功能齐全、开放的前端单元测试框架,支持 Babel、TypeScript、Node、React、Angular、Vue 等领域的单元测试,值得使用!

    能力有限,欢迎指正、互相交流,感谢~

    如果本文对您有帮助,麻烦动动手指点点赞?

    谢谢!

    相关文章

      网友评论

          本文标题:Jest:优雅的前端单元测试框架

          本文链接:https://www.haomeiwen.com/subject/pfbmzrtx.html