今天看啥  ›  专栏  ›  muwoo

前端单测的那些事

muwoo  · 掘金  ·  · 2018-08-20 09:55
阅读 41

前端单测的那些事

前言

因为经常需要维护一些大型的业务项目和一些自己的开源项目,所以为了更好的“规范”代码质量和迭代的稳定性,开始写了一些单测。下面也主要是自己的一些总结吧,由于测试工具和框架很多,这里只介绍一些browser端常用的测试工具,文中如果有问题也欢迎拍正!!🙂

为何要测试

之前我们开发项目的时候,总是会忽略去写一写单测,大多数原因可能是觉得没有时间或者是浪费时间。而且还需要去维护测试用例。 其实一般项目随着时间的迁移,会变得越来越复杂和庞大,这时候如果我们对某一个公共模块改动,而其他人也依赖了这个模块,可能就会导致别人的功能出现bug。 有了自动化测试,开发者会更加信任自己的代码。开发者再也不会惧怕将代码交给别人维护,不用担心别的开发者在代码里搞“破坏”。后人接手一段有测试用例的代码,修改起来也会更加从容。测试用例里非常清楚的阐释了开发者和使用者对于这端代码的期望和要求,也非常有利于代码的传承。

一些概念

TDD (Test Driven Development)

TDD 也就是测试驱动开发,简单的说,即在写任何功能代码之前,先写它的测试代码。具体步骤:

  • 根据需要编写一个测试用例
  • 编写功能代码,以让刚才的测试用例通过
  • 逐步补充测试用例
  • 修改功能代码使新增的测试用例和原来的都通过
  • 重构,包括功能代码和测试用例

BDD(Behaviour Driven Development)

BDD 即 行为驱动开发,可以理解为也是 TDD 的分支,即也是测试驱动,但 BDD 强调的是写测试的风格,即测试要写得像自然语言,运用一些比如expect、should等跟自然语言相近的断言,让项目的各个成员甚至产品都能看懂测试,甚至编写测试。

写法对比

不管是 TDD 还是 BDD,我们来对比一些二者的写法:

  // TDD
  suite('Array', function() {
    setup(function() {
    });

    test('equal -1 when index beyond array length', function() {
      assert.equal(-1, [1,2,3].indexOf(4));
    });
  });

  // BDD
  describe('Array', function() {
    before(function() {
    });

    it('should return -1 when no such index', function() {
      [1,2,3].indexOf(4).should.equal(-1);
    });
  });
复制代码

简单的看, BDD 风格写的会更容易理解,更加语义化。

断言(assert)

在单元测试时,开发预计在程序运行到某个节点位置,需要判断某些逻辑条件必须满足,这样下面的一些业务逻辑才可以进行下去,如果不满足,程序就会"报错"甚至是"崩溃"。断言在单测中,也是主要用来确定某段程序执行结果应该是某个值这样的一个预期。

一些断言库的比较

断言库即提供一套 API 帮助开发者在单元测试的过程中判定某个值是否符合预期,比如:

should.js
  value.should.equal(1);
  value.should.be.an.Object();
复制代码
expect.js
expect(value).to.be(1)
expect(value).to.be.an('object')
复制代码

chai

Chai is a BDD / TDD assertion library for node and the browser that can be delightfully paired with any javascript testing framework.

chai 提供了三种断言风格来分别适用于 BDD 和 TDD。expect/should API 对应BDD风格,Assert API 对应TDD风格。

image

测试框架

所谓"测试框架",就是运行测试的工具。通过它,可以为JavaScript应用添加测试,从而保证代码的质量。

Mocha

Mocha(发音"摩卡")诞生于2011年,是现在最流行的JavaScript测试框架之一,在浏览器和Node环境都可以使用。 更多关于mocha的使用和介绍可以参考阮老师的这篇文章测试框架 Mocha 实例教程

Jasmine

Jasmine 不依赖于任何框架,所以适用于所有的 Javascript 代码。使用一个全局函数 describe 来描述每个测试,并且可以嵌套。describe函数有2个参数,一个是字符串用于描述,一个是函数用于测试。在该函数中可以使用全局函数it 来定义Specs,也就是单元测试的主要内容, 使用 expect 函数来测试:

describe("A suite is just a function", function() {
  var a;
  it("and so is a spec", function() {
    a = true;
    expect(a).toBe(true);
  });
});
复制代码

前端测试工具

相比于服务端开发,前端开发在测试方面始终面临着一个严峻的问题,那就是浏览器兼容性。前端开发中浏览器兼容性是一个永远的问题,而且我认为即使解决了浏览器的兼容性问题,未来在移动开发方面,设备兼容性也是一个问题。

所以在自动化测试方面也是如此,即使所有的单元测试集中在了一个runner中,前端测试仍然要面对至少4个浏览器内核以及3个电脑操作系统加2个或更多移动操作系统,何况还有令移动开发人员头疼的Android的碎片化问题。不过可以安心的是,早已存在这样的工具可以捕获不同设备上的不同浏览器,并使之随时更新测试结果,甚至可以在一个终端上看到所有结果。下面我们主要介绍 Karma

Karma

Karma是一个基于 Node.js 的 JavaScript 测试执行过程管理工具(Test Runner)。该工具可用于测试所有主流Web浏览器,也可集成到 CI(Continuous integration)工具,也可和其他代码编辑器一起使用。这个测试工具的一个强大特性就是,它可以监控(Watch)文件的变化,然后自行执行,通过console.log显示测试结果。

文档

Istanbul

测试的时候,我们常常关心,是否所有代码都测试到了。 这个指标就叫做"代码覆盖率"(code coverage)。它有四个测量维度。

  • 行覆盖率(line coverage):是否每一行都执行了?
  • 函数覆盖率(function coverage):是否每个函数都调用了?
  • 分支覆盖率(branch coverage):是否每个if代码块都执行了?
  • 语句覆盖率(statement coverage):是否每个语句都执行了?

这个软件以土耳其最大城市伊斯坦布尔命名,因为土耳其地毯世界闻名,而地毯是用来覆盖的。

详细的文档参考阮老师的代码覆盖率工具 Istanbul 入门教程

动手!

下面我们来搭建一个ES6 + jasmine + karma + Istanbul + webpack 的基础测试工具。 首先来搭建一个简单的es6环境:

mkdir example

cd example

npm i babel-core bable-loader babel-preset-env --save
复制代码

然后创建.babelrc文件

{
    "presets": [
        "env"
    ]
}
复制代码

接着我们需要安装 karma 测试工具:

$ npm install karma --save-dev

$ npm install karma-jasmine karma-chrome-launcher jasmine-core --save-dev
复制代码

接下来初始化karma:

karma init
复制代码

image

这样目录中便会多了一个karma.conf.js这样的一个文件。为了在测试的时候可以使用es6,我们需要使用karma-webpack

npm i webpack karma-webpack --save
复制代码

接下来,就是我们熟悉的工作了,写一个加载测试脚本的webpack配置文件,比如webpack.test.js:

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      }
    ]
  }
};
复制代码

再改写一下我们的karma.conf.js, 引入webpack:

const webpack = require('../webpack.config')

module.exports = function(config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine'],
    files: [
      'test/**/*.spec.js'
    ],
    exclude: [
    ],
    preprocessors: {
      'test/add.spec.js': ['webpack']
    },
    webpack: webpack,
    reporters: ['progress'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['Chrome'],
    singleRun: false,
    concurrency: Infinity
  })
}
复制代码

运行karma start

image

当前我们的reporters设置的是progress,所以只会展示最终测试结果,和执行错误的语句。如果你想看到每一条的执行结果,可以安装karma-spec-reporter

npm install karma-spec-reporter --save-dev
复制代码

然后加入spec到karma.conf.js 的 reporters中:

reporters: ['spec']
复制代码

这样就会生成这样的形式报告:

image

其次我们需要添加istanbul进行代码覆盖率测试。首先我们需要安装一个babel插件:

npm install babel-plugin-istanbul --save-dev 
复制代码

然后修改我们的.babelrc文件:

{
  // ...
  "env": {
    "test": {
      "presets": ["env"],
      "plugins": ["istanbul"]
    }
  }
}
复制代码

通过使用.babelrc里的env属性,当我们通过设置BABEL_ENV=test的时候便可以去执行代码测试的相关插件,这在复杂项目中的测试配置中很有用。 接下来,为了能生成覆盖率测试报告,我们还需要安装一个 karma Istanbul 插件karma-coverage:

npm install karma karma-coverage --save-dev
复制代码

然后我们改一下package.json里面的script脚本:

"scripts": {
    "test": "cross-env BABEL_ENV=test karma start test/karma.conf.js"
}
复制代码

运行

npm run test
复制代码

打开 coverage里面的index.html文件:

image

可以看到覆盖率的一些测试结果。但是这样有点不太方便,希望能可以直接在控制台输出就好了。所以我们需要改一下karma.conf.js文件,加上这样一个属性:

coverageReporter: {
    dir: './coverage',
    reporters: [
        { type: 'lcov', subdir: '.' },
        { type: 'text-summary' } // 在控制台输出摘要
    ]
}
复制代码

这样我们在控制台便可以打印出基本的覆盖率测试结果:

image

至此。已经完成了一个测试环境的搭建,可以满足大部分工程的单测配置。

结语

可能平时由于大家更加关心业务代码,而会忽略一些前端的测试工作,网上的资料也是零零碎碎的,没有一个系统的总结和介绍。这里整理了一些测试工具的使用方法,希望可以对你有所帮助。然后本文所有代码和原始出处发表在个人博客中。也欢迎阅读之前的博文:

muwoo 的 blogs

单测demo

参考文章

测试框架 Mocha 实例教程

代码覆盖率工具 Istanbul 入门教程

Node.js 单元测试:我要写测试

关于前端开发谈谈单元测试




原文地址:访问原文地址
快照地址: 访问文章快照