每周获取最新的 Wordpress 资源

前端中的测试

前端为什么要有测试?

实际上前端开发的历史很短,因此普遍缺乏一些工程师的严谨和匠心,大部分前端工程师真的很少做过测试,一方面项目通常没有要求,另一方面对于测试认识不足,认为没有必要。

然而测试却是保证工程质量的关键一环。

首先,测试驱动开发会让我们尽可能早地考虑我们期待程序达到什么目标,也可以尽可能早地考虑各种可能的 bug 或者说边界条件,这一点非常重要,因为一个 bug 被发现的越迟,修复的代价会越高。单元测试就是编写测试用例,让我们的程序模块接受检验,从而尽可能多地以及尽可能早地保证对程序整体质量和稳定性的把控。

篱笆筑得牢,邻居处得好,WEB 应用程序也是如此,不管是何种编程准则,好的测试铸就好的代码。当然一定要是好的。

优秀的测试用例具有三个重要特征:

  • 反复性(repeatability),多次运行测试应该产生相同的结果,如果不确定,就不知道哪些结果是有效的,哪些又是无效的。另外,反复性可以确保我们的测试不依赖于外部因素(诸如网络或 CPU 负载)
  • 简单性(simplicity),测试应该只专注于测试一件事。在不影响测试用例的情况下,消除尽可能多的代码,那么测试用例只受特定代码的可能性就越大。
  • 独立性(independence),测试用例应当独立执行,避免一个测试结果依赖于另外一个。需要把测试分解成尽可能小的单元,这将帮我们确定在错误发生时的确切代码位置。

TDD 与 BDD

TDD 即测试驱动开发(Test-Driven Development),BDD 是行为驱动开发(Behavior Driven Development)

TDD 从测试的角度来检验整个项目。大概的流程是先针对每个功能点抽象出接口代码,然后编写单元测试代码,接下来实现接口,运行单元测试代码,循环此过程,直到整个单元测试都通过。

然而,在 TDD 中,我们并不能完全保证根据设计所编写的测试就是用户所期望的功能。BDD 将这一部分简单和自然化,用自然语言来描述,让开发、测试、BA 以及客户都能在这个基础上达成一致。因为测试优先的概念并不是每个人都能接受的,可能有人觉得系统太复杂而难以测试,有人认为不存在的东西无法测试。所以,我们在这里试图转换一种观念,那便是考虑它的行为,也就是说它应该如何运行,然后抽象出能达成共识的规范。

可以说,BDD 是对 TDD 的一种补充。

测试的核心

断言(assert)可以说是测试的核心。那么断言是什么?即表达程序设计人员对于系统应达到状态的一种预期。

很多语言都内置了断言 API,比如说 NodeJS 中便带有 Assert API,就连我们常用的浏览器控制台,也带有断言方法 console.assert

可以说有了断言就可以做测试了。举个例子,在 NodeJS 环境中我们要比较下面 a 和 b 两个对象是否相等

var a = {
  c: {
    e: 1
  }
};
var b = {
  c: {
    e: 1
  }
};

在 NodeJS 环境中,我们只需要这样做就可以测试出结果

assert.deepEqual(a, b);

测试框架

在正式做测试之前有两个问题,第一个,既然有断言就可以做测试,我们为什么要使用测试框架?第二个,前端测试框架也很多,比如说:Mocha,Jest,Jasmine,Chai,Should,Karma,它们各自作用是什么,如何配合使用?

第一个问题,为啥要用测试框架,要回答这个问题,可以反过来思考,如果不用测试框架,我们的测试代码是污染源代码的,是零散的,也都是手动测试的。如果用了测试框架呢?我们可以把测试代码,抽离出来,作为一个整体结构化地去设计测试用例,放置到专门测试文件,然后也可以实现自动运行以及显示测试结果。

第二个问题,MochaJestJasmineChaiShould.jsKarma 这些测试框架做啥用的

Mocha,Jest,Jasmine 可以说都是测试框架,可以达到之前说的,抽离,结构化,自动运行等等,其中 Jest 是一个相当全面的框架,且零配置,同时需要注意的是 Jest 也是基于 Jasmine 的,所以 Jest 的一些语法和 Jasmine 一模一样,连报错有时都会相同。

Chai,Should 都属于断言库,它们的 API 相对测试框架自带的断言 API 更加语义化,更好用,可以和上面的测试框架结合着用。

Karma 是一个 Test-Runner,可以说是凌驾测试框架之上,可以让给你的浏览器自动跑所有的测试用例。

综上所述,这些都可以根据各自的功用自由组合,下面以 Mocha,Should 和 Karma 组合为例

  • 局部安装 Mocha,Should 和 Karma npm install mocha should karma karma-mocha karma-chrome-launcher karma-firefox-launcher --save-dev
  • 初始化测试 npm run init
    1. Which testing framework do you want to use ? (mocha)
    2. Do you want to use Require.js ? (no)
    3. Do you want to capture any browsers automatically ? (Chrome)
    4. What is the location of your source and test files ? (需要加载的相关源文件和测试文件地址)
    5. Should any of the files included by the previous patterns be excluded ? ()
    6. Do you want Karma to watch all the files and run the tests on change ? (yes)
  • 启动测试 npm t
  • 编写测试用例,写代码,跑通测试

集成测试和测试覆盖率

开源项目做集成测试和测试覆盖率基本都是使用的是 Travis CIcoveralls.io

接着上面,我们开始做集成测试和测试覆盖

集成测试实例

首先讲讲如何在 karma 中做集成测试

karma.conf.js 的配置中需要注意的就是,将 singleRun 在 Travis 环境中修改成 true

module.exports = function(config) {
  config.set({
    ...
    singleRun: process.env.TRAVIS,
    ...
  })
}

如果同时测试 Chrome 和 Firefox,则对于 .travis.yml 的推荐配置是

language: node_js
node_js:
  - stable
sudo: required
addons:
  chrome: stable
  firefox: latest
before_script:
  - export DISPLAY=:99.0
  - sh -e /etc/init.d/xvfb start
  - sleep 3

更多说明参考以下链接

测试覆盖率实例

下面再讲讲如何在 karma 中做测试覆盖率

在开始配置之前,使用你的 Github 账户登陆授权 coveralls.io 这个站点,然后开启该测试项目所在仓库

第一步,安装 karma-coveragekarma-coveralls,karma-coverage 依赖包含 Istanbul,但是不用重复安装 Istanbul。karma-coveralls 用于将 karma-coverage 生成的测试覆盖率报告上传到 coveralls.io

npm i karma-coverage karma-coveralls --save-dev

第二步,修改 karma.conf.js 的配置

module.exports = function(config) {
  config.set({
    ...
    // source files, that you wanna generate coverage for
    // do not include tests or libraries
    // (these files will be instrumented by Istanbul)
    preprocessors: {
        'quz/*.js': ['coverage']
    },
    // coverage reporter generates the coverage
    reporters: ['progress', 'coverage', 'coveralls'],

    // optionally, configure the reporter
    coverageReporter: {
      type : 'lcov',
      dir : 'coverage/'
    },
    ...
  })
}

最后,每当 Travis 集成测试完成,coveralls 的测试覆盖率也会完成。

总结

以上是最近前端测试的一些实践和总结,有什么错误请不吝啬指教。

You May Also Like

About the Author: ted

发表评论

电子邮件地址不会被公开。 必填项已用*标注