测试你的前端代码 - part2(单元测试)

《测试你的前端代码 - part2(单元测试)》

本文作者:Gil Tayar
编译:胡子大哈

翻译原文:http://huziketang.com/blog/posts/detail?postId=58d3de1e7413fc2e8240855b
英文衔接:Testing Your Frontend Code: Part II (Unit Testing)

转载请说明出处,保存原文链接以及作者信息

上一篇文章《测试你的前端代码 – part1(引见)》中,我引见了关于前端测试的基本知识,从本文最先将详细引见测试手艺。

单元测试

上一节有讨论过,单元测试就是以代码单元为单元举行测试,代码单元可所以一个函数,一个模块,或许一个类。许多人以为大多数测试都应当叫单元测试,实在我的看法照样那句话,无所谓怎样叫,名字叫什么都行。只需你做了足够多的测试,能够保证你布置到线上的临盆代码没有题目就能够了。

单元测试是最轻易明白、也最轻易完成的测试体式格局。给单元测试一个输入,让它自动实行,将输出效果和预期效果做对照看其是不是准确(输入可所以一个函数参数,输出就是函数的返回值)。

在写单元测试的时刻,只管将你的单元测试自力出来,不要几个单元相互援用。养成如许优越的测试习气。

测试 Calculator 运用

第一节中提到过,为了这系列博文,我写了一个盘算器运用,背面都邑拿它举行测试。理论就讲到这里,一同来看一下 Calculator 运用吧,源代码在这里。重要有两个组件: keypad display ,它们自身都是 React 单元,也都没有援用其他单元,背面会引见怎样对它们举行测试。

(假如你已看了代码能够已发现了我没有运用 JSX。由于我不想举行转译。如今 Node 和一切盛行的浏览器都已完整支撑 ES6 了,那末作为一个例子来说,让它直接运转会更好一些。虽然它不能运转在 IE 上,不过也没紧要,假如是一个实在的线上项目,我会举行转译的。)

另有一个题目是按键和展现的逻辑题目,必须要有代码来掌握当点击按键的时刻发作什么。这里的按键包括数字键(如“1”,“5”)和操纵键(如“+”,“=”)。按平常的做法,我把组件设想成了展现型组件(键盘)和容器型组件。容器型组件在我的 App 中是唯一包括 state 的组件,它要斟酌当发作按键行动的时刻 App 内涵逻辑的题目。

“calculator”模块

处置惩罚逻辑题目的代码是一个零丁的模块——calculator。这个模块关于单元测试是很圆满的例子。由于它没有对 I/O 和 UI 的依靠。你也应当只管使你的运用逻辑上坚持自力——模块不依靠于 I/O 和 UI。

关于 Web 运用来说,I/O 是什么?没有文件和数据库的操纵?实在不仅仅是如许,另有 Ajax 挪用,当地存储,DOM 操纵等,对我而言,任何和浏览器 API 有关的都是 I/O 操纵。

我是怎样把盘算逻辑从 React 组件中星散出来的呢?实在很简朴,其内涵逻辑是盘算,我把他封装到一个模块中就能够了。

这个模块的完成也很轻易——它吸收一个盘算器 state(一个对象)和一个字符(数字或许操纵符),返回一个新的盘算器 state。假如你用过 Redux,它很像 Redux 的 reducer 形式(假如你没用过 Redux 也没紧要)。然则假如一向由上一个 state 猎取下一个 state,怎样能回到初始状况呢?这里另有一个模块叫做 initialState,经由过程它能够初始化盘算器。盘算器的 state 并非完整黑盒的,它包括了一个字段叫做 display,能够把你想要展现的 state 显现在盘算器运用上。

假如你没有耐烦看源代码的话,我们一同来看下这内里最重要的部份,运用中算法的细节实在不重要。

    module.exports.initialState = { display: '0', initial: true }
    
    module.exports.nextState = (calculatorState, character) => {
      if (isDigit(character)) {
        return addDigit(calculatorState, character)
      } else if (isOperator(character)) {
        return addOperator(calculatorState, character)
      } else if (isEqualSign(character)) {
        return compute(calculatorState)
      } else {
        return calculatorState
      }
    }
    
    //....

再次强调这里的完成细节并不重要,重要的是模块的设想,它暴露出来的函数异常简朴——给一个 state,获得下一个 state。

这就是我们在 test-calculator 中所做的事变。那末接下来怎样举行测试呢?运用测试框架,现在比较盛行的框架是 Mocha ,我们就用它。不过像 Jest,Jasmine,Tape等框架也都行,随便运用你喜好的测试框架。

用 Mocha 举行单元测试

一切的测试框架都相似,写测试代码挪用被测函数,经由过程测试框架运转他们,个中运转它们的代码平常叫做“runner”。

Mocha runner 叫做 “mocha”,假如你看测试剧本的 package.json,能够看到:

    "scripts": {
    ...
        "test": "mocha 'test/**/test-*.js' && eslint test lib",
    ...
    },

它会运转 test 文件夹中一切以 test- 开首的文件,你能够复制我的 repo,npm install 后,运转 npm test 自身尝尝。

(趁便提一句,把一切测试都放在测试目次,而且测试目次放在 package 的根目次是一个公认的 npm package 商定,假如你不想让人以为你不专业的话,最好照样恪守这一商定。)

运转它,会获得以下输出:

《测试你的前端代码 - part2(单元测试)》

这里有 14 个测试经由过程的提醒信息,假如没经由过程,就会有赤色提醒涌现。

我们看下面代码:

    const {describe, it} = require('mocha')
    const {expect} = require('chai')
    const calculator = require('../../lib/calculator')
    
    describe('calculator', function () {
      const stream = (characters, calculatorState = calculator.initialState) =>
        !characters
          ? calculatorState
          : stream(characters.slice(1),
                   calculator.nextState(calculatorState, characters[0]))
    
      it('should show initial display correctly', () => {
        expect(calculator.initialState.display).to.equal('0')
      })
      it('should replace 0 in initialState', () => {
        expect(stream('4').display).to.equal('4')
      })
    //...

起首引入 mocha 和断言常量 expect,这里只引入我们须要的函数:describeitexpect。接下来引入我们要测试的模块 calculator

预备最先测试,用 it 函数来表达:

    it('should show initial display correctly', () => {
        expect(calculator.initialState.display).to.equal('0')
    })

it 函数吸收一个字符串(用来示意测试效果)和一个函数(待测函数)。it 测试不能零丁运转,它们必需构成一个测试组。所以如代码中所示,用 describe 函数定义测试组,内里包括了若干个 it 函数。

测试函数中写什么呢?能够写任何想写的东西,在这个例子中我们测试了初始状况所显现的是不是是 0。假如我们自身来完成怎样完成呢,比方能够像以下代码:

    if (calculator.initialState.display !== '0')
      throw 'failed'

关于这个题目,上面代码也是能够测出来的。然则 expect 包括了许多特征能够使测试变得更简朴,比方能够测试数组或许对象是不是和一个给定的值相称。这就是单元测试的要点,即运转一个函数,或一组函数,搜检其 运转效果 是不是和 预期效果 一致。

编写单元可测的代码

上面的很简朴对吧!实在关于单元测试来说,难的并非单元测试自身,而是星散代码的艺术,把代码只管星散成单元可测的模块。单元可测的代码平常都是不依靠于其他模块、不依靠于 I/O 的代码。这是比较难题的,大多数人都倾向于把逻辑代码、I/O 代码和 UI 代码写到一同。难题是难题,但不是说做不到,有许多技能能够运用,比方你的代码中有一些考证字段,那末你就能够把考证代码构造到一同形成函数,再对这个考证函数举行测试。

测试代码是运转在 NodeJS 下的!?

注重一个重要的事变——单元测试是在 NodeJS 下运转的!而盘算器运用是运转在浏览器端的,上面的临盆代码都是在 NodeJS 下举行测试的,这也能够吗?

固然能够。由于我们的代码是同构的,它能够运转在浏览器端和 NodeJS 上。假如你的代码没有运用任何 I/O,就是说没有对浏览器做任何的特化处置惩罚,那末它就没有来由不能运转在 NodeJS 上。别的,假如你运用了 require,它既能够被当地的 NodeJS 辨认,也能够被像 Webpack 一样的打包器辨认。你看代码中的 package.json,就能够看到我们就是运用了 Webpack,用 require 举行代码打包:

    "scripts": {
       "build": "webpack && cp public/* dist",
       ...
    }

代码中运用 require 来引入 React 或许其他模块,这不论是在 NodeJS 中照样浏览器中都是通用的。

在浏览器中运转单元测试

我们还能够运用另一个测试框架,Karma 。运用它能够在浏览器中运转 Mocha 代码,然则这里表达一下我的肤见:单元测试能在 Node 下运转就在 Node 下运转,由于很轻易实行和 debug(固然如今在浏览器中实行也很轻易)。而且假如代码不须要转译的话,实行的也异常快。

然则我们的代码没有在浏览器中测试确实是个题目,由于我们并不真正地晓得代码在浏览器中运转会是什么模样。浏览器中的 JS 实行环境和 NodeJS 环境能够会有玄妙的差异。

总结

本文中重要引见了什么:

  • 引见了怎样运用 Mocha (和 Chai)建立单元测试;

  • 引见了单元测试就是以代码单元为单元举行测试,这个代码单元是自力于其他模块的。

  • 引见了设想模块时应当自力于其他模块。假如肯定要有依靠,那末能够 mock 一个其他模块对本模块举行单元测试,或许举行集成测试。

  • 引见了我们测试的代码单元应当是同构的,如许就能够在 NodeJS 环境下举行测试了。

  • 引见了怎样写同构代码——没有 I/O操纵、运用 require 引入模块、运用 Webpack 来打包模块以使其相符浏览器运转环境。

下文简介

下篇文章我们引见端到端测试,把我们的代码在实在环境(浏览器)中测试。请看下一篇文章《测试你的前端代码 – part3(端到端测试)》

我近来正在写一本《React.js 小书》,对 React.js 感兴趣的童鞋,迎接指导

    原文作者:胡子大哈
    原文地址: https://segmentfault.com/a/1190000008823413
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞