从零开始的中大厂前端项目落地(三)

1,346 阅读8分钟

我正在参加「掘金·启航计划」

从零开始的中大厂前端项目落地(三)

落地一个前端项目涉及非常多知识,因此从6个角度入手,化整为零,逐个击破:

  1. 选择合适的构建工具
  2. 定制团队代码规范
  3. 测试工具
  4. 封装自己的组件
  5. 自动部署
  6. 安全


如何做前端测试

测试可以包含多个维度,如单元测试兼容性测试黑盒测试等。本章主要介绍单元测试,测试驱动开发可以帮助开发者找到遗漏的逻辑从而更好地完成开发,同时在后续迭代中也能保证不会引入缺陷。

随着代码行数的增多,Bug 在所难免,而避免 Bug 最好的方法就是进行测试对于库来说,每次改动代码都要进行全面的测试。特别是当要对项目代码进行重构时测试能够降低重构的风险。但是,如果每次都通过人工进行测试,则既浪费时间又容易出错,更好的做法是编写代码来测试代码,因为代码能够快速多次运行,并且稳定可靠,这种方法被称作单元测试。

对核心组件覆盖自动化测试,可以有效地保证组件功能的单一,起到警醒工程师的作用,而不至于让不同的业务代码相互耦合;新同学可以通过单测快速 get 到这个组件打算做什么、有什么能力,不论是后续的维护还是重构都会更有底气。

通过测试来保证和提升代码质量。设计单元测试用例的方法有两种,分别是测试驱动开发(Test DrivenDevelopmentTDD)和行为驱动开发 (Behavior Driven DevelopmentBDD)。

JavaScript 中的单元测试有很多技术方案,每种方案都有自己的优点和适应场景。类似 React 之类的框架都提供了默认的测试方案,如果要写 React 的项目,那么直接使用框架推荐的测试方案即可。下图是双越老师在某个课程里面写的测试代码:

企业微信截图_16770334438805.png

对于通用的基础建设,相比手工测试,自动化测试的覆盖率更有说服力,并且可以有效规避某次修改引起的历史功能的异常,从而保证整体功能的稳定。

想必大家也知道自动化测试的重要性。其实,对于前端工程师而言,最大的痛点在于,不知道该怎么去写对应的测试用例。而如何在项目中使用测试代码,将通过以下点讲述:

  • 测试工具的选型
  • Jest
  • 设计测试用例


测试工具的选型

Mocha

Mocha 是一个功能丰富的 JavaScript 测试框架,运行在 Node.js浏览器 中,使异步测试变得简单有趣Mocha 也是历史比较悠久的测试框架,其相对比较成熟,并且使用范围广泛,兼容性能够满足我们的要求。虽然 Mocha 可以提供组织和运行单元测试并输出测试报告的功能,但是要进行单元测试还需要一个断言库,Mocha 推荐使用 Chai 作为断言库。由于 Chai 不能够兼容 IE8 浏览器,因这里使用另一个断言库--expet.jsexpect.js 是一个 BDD 体系的断言库,兼容性非常好,甚至可以支持 IE6 浏览器。

接下来我们在项目中安装一下 Mocha,注意:Mocha (version:10+)需要 Node (version:14+)

npm install --save-dev mocha

然后在文件夹添加一个测试用的 js 文件:

var assert = require('assert');
    describe('Array', function () {
    describe('#indexOf()', function () {
        it('should return -1 when the value is not present', function () {
            assert.equal([1, 2, 3].indexOf(4), -1);
        });
    });
});

这里的 assert 需要 require 一下,然后再打开命令行工具,通过下面的命令执行测试。其中,npx 前缀表示寻找当前路径下的 node modules 目录下的 mocha 命令并执行,如果不使用 npx,则需要通过路径来引用。下面三种命令的效果是等价的,推荐使用 npm run 方式来执行。

// 直接用npx运行
npx mocha

// 通过bin运行
./node_modules/mocha/bin/mocha

// 在package.json添加scripts运行
npm run test

企业微信截图_16771194303982.png

可以看到我们刚刚写的测试已经 passing,即代表我们的测试通过了。

Jest

Jest因为只带了 expect,所以在写测试的时候不用额外引入断言了。我们在项目里面试一下吧,这一次我们建一个 js工具库,这个 sum.js简单的求和工具。

npm install --save-dev jest
function sum(a, b) {  
    return a + b;  
}  
module.exports = sum;

然后我们开始编写测试代码,新建一个 sum.test.js文件:

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

然后再运行一下,也是 pass

企业微信截图_16771204467922.png


Jest也能在 vscode 上使用, vscode-jest,这个插件能自动识别 vscode 上的项目,并且可以显示代码通过率。

image.png

企业微信截图_16771348065986.png



使用Jest

通过上面的 Jest 示例,可以发现测试代码调用了 expect 方法,expect 接收一个参数,输入参数即要测试的对象,如 sum 函数。接着通过链式调用 toBetoBe 用于比较原始值或检查对象实例的引用标识。它调用Object.is比较值,这比严格的相等运算符更适合测试===

回到上面的例子中,sum 输入 1 和 2,期望 sum 处理后输出 3,那么我们就在测试文件写上 .toBe(3),接下来就用程序自己去跑就可以了。

用断言的使用场景可以分成以下六个方向:

基础类型的比较
涉及的断言Api 解析 示例
not 用来表示非的判断 expect(1 + 1).not.toBe(3);
toBe(value) 基础类型的判断 expect(true).toBe(true);
toBeTruthy(value) 六个假值:false、0、''、null、undefined和NaN。其他一切都为真 expect(true).toBeTruthy();
toBeFalsy(value) 和toBeTruthy相反 expect(true).toBeFalsy();
toBeDefined() 检查变量是否未定义 expect(undefined).not.toBeDefined();
toBeUndefined() 检查变量是否未定义 expect(undefined).toBeUndefined();
toBeCloseTo(value) 比较浮点数是否近似相等 expect(0.2 + 0.1).toBeCloseTo(0.3);
toBeNaN() 检查值是否为NaN expect(NaN).toBeNaN();


引用类型的比较
涉及的断言Api 解析 示例
toEqual(value) 深度递归对象的每个属性,进行深度比较,只要原始值相同,那就可以通过断言 expect({ obj1: { name: "obj1" } }).toEqual(Object.assign({ obj1: { name: "obj1" } }));


数字符号
涉及的断言Api 解析 示例
toEqual(value) 解析
toBeLessThan(value) 大于某个整数(received > expected) expect(3).toBeGreaterThan(2);
toBeGreaterThanOrEqual(value) 大于等于某个整数(received >= expected) expect(3).toBeGreaterThanOrEqual(3);
toBeLessThanOrEqual(value) 小于于某个整数(received <= expected) expect(3).toBeLessThanOrEqual(4);


正则匹配
涉及的断言Api 解析 示例
toMatch(value) 检查字符串是否与正则表达式匹配 expect("This is a regexp validation").toMatch(/regexp/);
toMatchObject(value) 验证对象能否包含 value 的全部属性,即 value 是否是匹配对象的子集 const obj = { prop1: "test", prop2: "regexp validation" };
const childObj = { prop1: "test" };
expect(obj).toMatchObject(childObj);


表单验证
涉及的断言Api 解析 示例
toContain(value) 判定某个值是否存在在数组中 expect([1, 2, 3]).toContain(1);
arrayContaining(value) 匹配接收到的数组,与 toEqual 结合使用可以用于判定某个数组是否是另一个数组的子集 expect([1, 2, 3]).toEqual(expect.arrayContaining([1, 2]));
toContainEqual(value) 用于判定某个对象元素是否在数组中 expect([{ a: 1, b: 2 }]).toContainEqual({ a: 1, b: 2 });
toHaveLength(value) 断言数组的长度 expect([1, 2, 3]).toHaveLength(3);
toHaveProperty(value) 断言对象中是否包含某个属性,针对多层级的对象可以通过 xx.yy 的方式进行传参断言 expect(testObj).toHaveProperty("prop1");


错误抛出
涉及的断言Api 解析 示例
toThrow() 测试函数在被调用时是否抛出 expect(throwError).toThrow();
toThrowError() 测试函数在被调用时是否抛出 expect(throwError).toThrowError();


设计测试用例 && 覆盖率指标

在编写代码之前需要先设计测试用例,测试用例要尽可能全面地覆盖各种情况,这样才能保证质量;在覆盖全面的同时,数量要尽可能少,这样能够提高测试效率。对于函数的测试,可以按照参数分组,每个参数一组,在对一个参数进行测试时,保证其他参数无影响。对于存在边界值情况的参数,还需要对边界值设计测试用例。

在编写单元测试时,如何保证所有代码都能够被测试到呢?设计测试用例的方法基本可以保证主流程的测试,但依然存在人为的疏忽和一些边界情况可能漏测的问题。代码覆盖率是衡量测试是否严谨的指标,检查代码覆盖率可以帮助单元测试查漏补缺。

覆盖率指标指的是测试用例覆盖文件的质量指标,通常指以下4个

指标名称指标内容
statement语句覆盖率,是不是每个语句都执行了
branch分支覆盖率,是不是每个 if 判断都执行了
function函数覆盖率,是不是每个函数都执行了
line行覆盖率,是不是每行都执行了


小结

本章介绍了单元测试相关的整套方案,其中涉及不少工具,读者不必一次掌握,配置好环境后关注自己的测试用例即可。此外,目前单元测试领域有了一些更新的技术值得关注,包括但不限于单元测试框架 Jest 和 UI 自动化测试框架 Cypress。在测试不同的库时可以用不同的测试方案,但单元测试是保证质量必不可少的流程,设计良好的测试用例和检查代码覆盖率是保证测试质量的方法。



最后,让我们一起加油吧!

gg.jpg

参考资料:

jestjs.io/
mochajs.org/
juejin.cn/book/717404…