CSDN首发网易云团队前端单元测试技术方案总结

单元测试技术方案很多,不同工具之间有互相协同,也存在功能重合,给我们搭配测试方案带来不小的困难,而且随着 ES6, TypeScript 的出现,单元测试又增加了很多其他步骤,完整配置起来往往需要很大的时间成本。我希望通过对这些工具的各自作用的掌握,了解完整的前端测试技术方案。前端单元测试的领域也很多,这里主要讲对于前端组件如何进行单元测试,最后会主要介绍下对于 React 组件的一些测试方法总结。

  通用测试

  单元测试最核心的部分就是做断言,比如传统语言中的 assert 函数,如果当前程序的某种状态符合 assert 的期望此程序才能正常执行,否则直接退出应用。所以我们可以直接用 Node 中自带的 assert 模块做断言。

  用最简单的例子做个验证:

  function multiple(a, b) {

      let result = 0;

      for (let i = 0; i < b; ++i)

          result += a;

      return result;

  }

  const assert = require('assert');

  assert.equal(multiple(1, 2), 3));

  这种例子能够满足基础场景的使用,也可以作为一种单元测试的方法。

  nodejs 自带的 assert 模块提供了下面一些断言方法,只能满足一些简单场景的需要。

  assert.deepEqual(actual, expected[, message])

  assert.deepStrictEqual(actual, expected[, message])

  assert.doesNotMatch(string, regexp[, message])

  assert.doesNotReject(asyncFn[, error][, message])

  assert.doesNotThrow(fn[, error][, message])

  assert.equal(actual, expected[, message])

  assert.fail([message])

  assert.ifError(value)

  assert.match(string, regexp[, message])

  assert.notDeepEqual(actual, expected[, message])

  assert.notDeepStrictEqual(actual, expected[, message])

  assert.notEqual(actual, expected[, message])

  assert.notStrictEqual(actual, expected[, message])

  assert.ok(value[, message])

  assert.rejects(asyncFn[, error][, message])

  assert.strictEqual(actual, expected[, message])

  assert.throws(fn[, error][, message])

  自带的 assert 不是专门给单元测试使用, 提供的错误信息文档性不好,上面的 demo 最终执行下来会产生下面的报告:

  $ node index.js

  assert.js:84

    throw new AssertionError(obj);

    ^

  AssertionError [ERR_ASSERTION]: 2 == 3

      at Object.<anonymous> (/home/quanwei/git/index.js:4:8)

      at Module._compile (internal/modules/cjs/loader.js:778:30)

      at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)

      at Module.load (internal/modules/cjs/loader.js:653:32)

      at tryModuleLoad (internal/modules/cjs/loader.js:593:12)

      at Function.Module._load (internal/modules/cjs/loader.js:585:3)

      at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)

      at startup (internal/bootstrap/node.js:283:19)

      at bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)

  由于自带的模块依赖 Node 自身的版本,没办法*升级,所以使用内置的包灵活性有时候不太够,另外我们很多断言函数也需要在浏览器端执行,所以我们需要同时支持浏览器和 Node 端的断言库。同时观察上面的输出可以发现,这个报告更像是程序的错误报告,而不是一个单元测试报告。而我们在做单元测时往往需要断言库能够提供良好的测试报告,这样才能一目了然地看到有哪些断言通过没通过,所以使用专业的单元测试断言库还是很有必要。

  chai

CSDN首发网易云团队前端单元测试技术方案总结

  chai 是目前很流行的断言库,相比于同类产品比较突出。chai 提供了 TDD (Test-driven development)和 BDD (Behavior-driven development) 两种风格的断言函数,这里不会过多介绍两种风格的优缺,本文主要以 BDD 风格做演示。

  TDD 风格的 chai

  var assert = require('chai').assert

    , foo = 'bar'

    , beverages = { tea: [ 'chai', 'matcha', 'oolong' ] };

  assert.typeOf(foo, 'string'); // without optional message

  assert.typeOf(foo, 'number', 'foo is a number'); // with optional message

  assert.equal(foo, 'bar', 'foo equal `bar`');

  assert.lengthOf(foo, 3, 'foo`s value has a length of 3');

  assert.lengthOf(beverages.tea, 3, 'beverages has 3 types of tea');

  chai 比 Node 自带的 assert 增加了一个断言说明参数,可以通过这个参数提高测试报告的可读性。

  $ node chai-assert.js

  /home/quanwei/git/learn-tdd-bdd/node_modules/chai/lib/chai/assertion.js:141

        throw new AssertionError(msg, {

        ^

  AssertionError: foo is a number: expected 'bar' to be a number

      at Object.<anonymous> (/home/quanwei/git/learn-tdd-bdd/chai-assert.js:6:8)

      at Module._compile (internal/modules/cjs/loader.js:778:30)

      at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)

      at Module.load (internal/modules/cjs/loader.js:653:32)

      at tryModuleLoad (internal/modules/cjs/loader.js:593:12)

      at Function.Module._load (internal/modules/cjs/loader.js:585:3)

      at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)

      at startup (internal/bootstrap/node.js:283:19)

      at bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)

  BDD 风格的 chai

  chai 的 BDD 风格使用 expect 函数作为语义的起始,也是目前几乎所有 BDD 工具库都遵循的风格。

  chai 的 expect 断言风格如下:

  expect(foo).to.be.a('string');

  expect(foo).to.equal('bar');

  expect(foo).to.have.lengthOf(3);

  BDD 的思想就是写单元测试就像写产品需求,而不关心内部逻辑,每一个用例阅读起来就像一篇文档。例如下面的用例:

  1.foo 是一个字符串              ->expect(foo).to.be.a('string')

  2.foo 字符串里包含 'bar'     ->expect(foo).to.include('bar')

  3.foo 字符串里不包含 'biz'  -> expect(foo).to.not.include('biz')

  可以看到这种风格的测试用例可读性更强。

  其他的断言库还有 expect.js should.js better-assert , unexpected.js 这些断言库都只提供纯粹的断言函数,可以根据喜好选择不同的库使用。

  有了断言库之后我们还需要使用测试框架将我们的断言更好地组织起来。

  mocha 和 Jasmine

  mocha 是一个经典的测试框架(Test Framework),测试框架提供了一个单元测试的骨架,可以将不同子功能分成多个文件,也可以对一个子模块的不同子功能再进行不同的功能测试,从而生成一份结构型的测试报告。例如 mocha 就提供了describe 和 it  描述用例结构,提供了 before, after, beforeEach, afterEach 生命周期函数,提供了 describe.only ,describe.skip , it.only, it.skip 用以执行指定部分测试集。

  const { expect } = require('chai');

  const { multiple } = require('./index');

  describe('Multiple', () => {

      it ('should be a function', () => {

          expect(multiple).to.be.a('function');

      })

      it ('expect 2 * 3 = 6', () => {

          expect(multiple(2, 3)).to.be.equal(6);

      })

  })

  测试框架不依赖底层的断言库,哪怕使用原生的 assert 模块也可以进行。给每一个文件都要手动引入 chai 比较麻烦 ,这时候可以给 mocha 配置全局脚本,在项目根目录 .mocharc.js 文件中加载断言库, 这样每个文件就可以直接使用 expect 函数了。

  // .mocharc.js

  global.expect = require('chai').expect;

  使用 mocha 可以将我们的单元测试输出成一份良好的测试报告 mocha *.test.js

CSDN首发网易云团队前端单元测试技术方案总结

  当出现错误时输出如下:

CSDN首发网易云团队前端单元测试技术方案总结

 

CSDN首发网易云团队前端单元测试技术方案总结

  因为运行在不同环境中需要的包格式不同,所以需要我们针对不同环境做不同的包格式转换,为了了解在不同端跑单元测试需要做哪些事情,可以先来了解一下常见的包格式。

  目前我们主流有三种模块格式,分别是 AMD, CommonJS, ES Module。

 最后为方便大家学习测试,特意给大家准备了一份13G的超实用干货学习资源,涉及的内容非常全面。

CSDN首发网易云团队前端单元测试技术方案总结
包括,软件学习路线图,50多天的上课视频、16个突击实战项目,80余个软件测试用软件,37份测试文档,70个软件测试相关问题,40篇测试经验级文章,上千份测试真题分享,还有2021软件测试面试宝典,还有软件测试求职的各类精选简历,希望对大家有所帮助……

关注我公众号:【程序员小濠】即可获取这份资料了!

如果你不想再体验一次自学时找不到资料,没人解答问题,坚持几天便放弃的感受的话,可以加入我们的群:175317069 大家一起讨论交流,里面也有各种软件测试资料和技术交流。
 

好文推荐

5年经验之谈:月薪3000到30000,测试工程师的变“行”记!

测试工程师,自动化测试工程师,测试开发工程师,这三个岗位分别需要掌握哪些能力和技术栈?

不要让毒鸡汤毁了你,35岁的测试员没有那么可怕,保持专注更重要

如果对你有帮助的话,点个赞收个藏,给作者一个鼓励。也方便你下次能够快速查找。

 

上一篇:js日志输出还是只会console.log么,那你就out了


下一篇:Assert断言