前端单元测试 工作笔记

单元测试

  • 定义: 单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。

  • 必要性: 在实际使用过程中会伴随着一大批的附带操作大量增加测试时间,并且无法保证其测试覆盖率。单元测试的目的并不仅仅是确认是否可用,而是更高效更稳定的确认其是否可用。一个函数在多个组件中被调用,但是由于当前组件的特殊性需要对函数进行加工,加工之后对原来的功能影响是未知的,如果一一将引用函数的功能全部测一遍,太浪费时间了,单元测试解决了重复测试相同函数不同功能的测试时间。测试不通过,根据需要,要么修改代码,要么修改测试

  • 意义: 这种以测试为驱动的开发模式(TDD)最大的好处就是确保一个程序模块的行为符合我们设计的测试用例。在将来修改的时候,可以极大程度地保证该模块行为仍然是正确的

命名规则

新建测试脚本 calcu.test.js,一般命名规则测试脚本和原脚本同名,但是后缀名为.test.js (.spec.js)

测试脚本的样子

var add = require('./add.js');
var expect = require('chai').expect;

describe('加法函数的测试', function() {
  it('1 加 1 应该等于 2', function() {
    expect(add(1, 1)).to.be.equal(2);
  });
});
  • 每一段测试脚本可以独立执行

  • 测试脚本里面应该包括一个或多个describe块,每个describe块应该包括一个或多个it块。

  • describe块称为"测试套件"(test suite),表示一组相关的测试。它是一个函数,第一个参数是测试套件的名称("加法函数的测试"),第二个参数是一个实际执行的函数。

  • it块称为"测试用例"(test case),表示一个单独的测试,是测试的最小单位。它也是一个函数,第一个参数是测试用例的名称("1 加 1 应该等于 2"),第二个参数是一个实际执行的函数。

  • 所谓"断言",就是判断源码的实际执行结果与预期结果是否一致,如果不一致就抛出一个错误。上面这句断言的意思是,调用add(1, 1),结果应该等于2

  • 一个单元测试里面可以包含多个断言语句

常见的测试类型

  • 常规函数的测试

  • 异步函数的测试

  • api测试

  1. 常规

export.add = (a,b) => {
    return a + b;
}

// 测试脚本如下 calcu.test.js
let calcu = require('./calcu');
let should = require('should');

describe('add func test', () => {
    calcu.add(2,2).should.equal(4);
})

// 运行
mocha calcu.test.js
  1. 异步

// 新建book.js
let fs = require('fs);
export.read = (cb) => {
    fs.readFile('./book.txt', 'utf-8', (err, result) => {
        if(err) throw err;
        cb(null, result);
    })
}

// 新建文件book.test.js
let book = require('./book');
let expect = require('chai').expect;

describe('async', () => {
    it('read book async', (done) => {
        book.read((err, result) => {
            expect(err).equal(null);
            expect(result).to.be.a('string');
            done(); // 告诉mocha测试结束
        })
    })
})

// 运行
mocha book.test.js
// 运行mocha book.test.js,我们会发现成功了,但是如果我们把book.js增加一个定时函数,改为如下例子
let fs = require('fs');

exports.read = (cb) => {
    setTimeout(function() {
        fs.readFile('./book.txt', 'utf-8', (err, result) => {
            if (err) return cb(err);
            console.log("result",result);
            cb(null, result);
        }) 
    }, 3000);
}

// 会发现报如下错误
// Timeout of 2000ms exceeded.

这是因为mocha默认每个测试用例最多执行2000毫秒,如果到时没有得到结果,就报错。所以我们在进行异步操作的时候,需要额外指定timeout时间


mocha --timeout 5000 book.test.js

// 指定了超时时间是5秒钟
  1. api测试
  • api 测试需要用到一个模块是supertest

// 安装
npm intall supertest --save-dev


// 新建文件 api.test.js
let expect = require('chai').expext;
let request = require("supertest");

describe('api', () => {
    it('get baidu information', function (done) {
        request('https://www.baidu.com')
            .get('/')
            .expect(200)
            .expect('Content-Type', /html/)
            .end(function (err, res){
                expect(res).to.be.an('object');
                done();
            })
    })
})

命令行参数详解

  • –reporter :用来指定报告的格式 默认spec 可以另外安装网页格式

  • -t 5000是因为我们测试用例中有一个异步执行过程,需要调高mocha的单元测试时间

  • –watch :参数用来监视指定的测试脚本。只要测试脚本有变化

  • –bail:参数指定只要有一个测试用例没有通过,就停止执行后面的测试用例

  • –grep:参数用来搜索单元测试用例的名称,然后运行符合搜索条件的测试用例,支持正则表达

  • –invert:参数表示只运行不符合条件的测试脚本,必须与–grep参数配合使用。

  • --recursive 一般如果运行mocha,会执行当前目录下的test目录的一级层级的所有js文件,但是test下的更多层级却没办法运行,这时就需要参数–recursive,这时test子目录下面所有的测试用例----不管在哪一层----都会执行

配置文件mocha.opts的配置

mocha的生命钩子

  • mocha一共四个生命钩子

before():在该区块的所有测试用例之前执行
after():在该区块的所有测试用例之后执行
beforeEach():在每个单元测试前执行
和afterEach():在每个单元测试后执行


typescript规定了数据的类型 测试解决了过程和结果的正确性


  • 目录的结构

  • 函数写法要求规范

  • 断言的框架

  • 测试框架解决问题?异同

  • dom

单元测试中应该避免

太多的条件逻辑

构造函数中做了太多事情

太多的全局变量

太多的静态方法

过多外部依赖

无关逻辑


测试代码时,只考虑测试,不考虑内部实现

数据尽量模拟现实,越靠近现实越好

充分考虑数据的边界条件

对重点、复杂、核心代码,重点测试

利用AOP(beforeEach、afterEach),减少测试代码数量,避免无用功能

测试、功能开发相结合,有利于设计和代码重构

测试框架的必要性

就像vue开发和原生开发一样 原生开发随着功能的不断增加,代码的维护和功能代码的添加变得越来越困难

测试代码也一样 单元测试也需要一种行之有效的实践来确保其质量和可维护性。

测试框架 简介 优点 不足
QUnit QUnit是jQuery团队开发的JavaScript单元测试工具,功能强大且使用简单。目前所有的JQuery代码都使用QUnit进行测试,原生的JavaScript也可以使用QUnit。 1.使用起来非常方便,有漂亮的外观和完整的测试功能(包括异步测试);   2.不需要依赖其它任何软件包或框架,只要能运行JS的地方就可以,QUnit本身只有一个JS文件和CSS文件,当然如果需要可以和jQuery等其它框架集成;   3.不仅支持在浏览器中测试,还支持在Rhino和node.js等后端测试。 对自动化支持不好,很难和Ant、Maven或自动构建等工具集成,主要用在浏览器中进行测试。 异步困难语法不流畅不好配置
jasmine Jasmine是一个有名的JavaScript单元测试框架,它是独立的行为驱动开发框架,语法清晰易懂。 1.它是基于行为驱动开发实现的测试框架,它的语法非常贴近自然语言简单明了容易理解2.它有丰富的API,同时用户也支持用户扩展它的API,这一点很少有其它框架能够做到。 在浏览器中的测试界面不如QUnit美观、详细。一异步测试麻烦
Mocha Mocha是一个简单、灵活有趣的JavaScript 测试框架,用于Node.js和浏览器上的JavaScript应用测试 1.支持简单异步,包括 promise;2.提供javascript API来运行测试;3.non-ttys自动检测和禁用颜色;4.支持异步测试超时;5.支持node debugger;6.高扩展性 部分领域缺少支持

断言库

  • chai是一套TDD(测试驱动开发)/BDD(行为驱动开发)的断言框架他包含有3个断言库,支持BDD风格的expect/should和TDD风格的assert,这里主要说明expect/should库,BDD风格说简单的就是你的测试代码更加的语义化,让你的断言可读性更好,expect/should库都支持链式调用

(测试驱动开发): 它要求在编写某个功能的代码之前先编写测试代码,然后只编写使测试通过的功能代码,通过测试来推动整个开发的进行。这有助于编写简洁可用和高质量的代码,并加速开发过程。测试驱动开发的基本过程如下:

1) 明确当前要完成的功能。可以记录成一个 TODO 列表。

2) 快速完成针对此功能的测试用例编写。

3) 测试代码编译不通过。

4) 编写对应的功能代码。

5) 测试通过。

6) 对代码进行重构,并保证测试通过。

7) 循环完成所有功能的开发。

(行为驱动开发): 使用通用语言,客户和开发者可以一起定义出系统的行为,从而做出符合客户需求的设计。但如果光有设计,而没有验证的手段,就无法检验我们的实现是不是符合设计。所以 BDD还是要和测试结合在一起,用系统行为的定义来验证实现代码。(有点厉害)

Mocha + Chai

import chai from 'chai';

const assert = chai.assert;
const expect = chai.expect;  // 这个比较贴合自然语言
const should = chai.should();
// -----------
foo.should.be.a('string');
foo.should.equal('bar');
list.should.have.length(3);
obj.should.have.property('name');

expect(foo).to.be.a('string');
expect(foo).to.equal('bar');
expect(list).to.have.length(3);
expect(obj).to.have.property('flavors');

assert.typeOf(foo, 'string');
assert.equal(foo, 'bar');
assert.lengthOf(list, 3);
assert.property(obj, 'flavors');

测试思路

基本思路:自身从函数的调用者出发,对函数进行各种情况的调用,查看其容错程度、返回结果是否符合预期。

目录

参考别人

参考vue-cli
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容