测试专题1:Javascript自动化集成测试基础概念

1. 为什么要写测试?

Web 应用程序越来越复杂,这意味着有更多的可能出错。测试是帮助我们提高代码质量、降低错误的最好方法和工具之一。

  • 测试可以确保得到预期结果。
  • 加快开发速度。
  • 方便维护。
  • 提供用法的文档。

通过测试提供软件的质量,在开始的时候,可能会降低开发速度。但是从长期看,尤其是那种代码需要长期维护、不断开发的情况,测试会大大加快开发速度,减轻维护难度。

2. 测试的类型

2.1 单元测试

单元测试(unit testing)指的是以软件的单元(unit)为单位,对软件进行测试。单元可以是一个函数,也可以是一个模块或组件。它的基本特征就是,只要输入不变,必定返回同样的输出。

“单元测试”这个词,本身就暗示,软件应该以模块化结构存在。每个模块的运作,是独立于其他模块的。一个软件越容易写单元测试,往往会暗示着它的模块化结构越好,各模块之间的耦合性就越弱;越难写单元测试,或者每次单元测试,不得不模拟大量的外部条件,很可能暗示软件的模块化结构越差,模块之间存在较强的耦合。

单元测试的要求是,每个模块都必须有单元测试,而软件由模块组成。

单元测试通常采取断言(assertion)的形式,也就是测试某个功能的返回结果,是否与预期结果一致。如果与预期不一致,就表示测试失败。

单元测试是函数正常工作、不出错的最基本、最有效的方式之一。每一个单元测试发出一个特定的输入到所要测试的函数,看看函数是否返回预期的输出,或者采取了预期的行动。单元测试证明了所测试的代码行为符合预期。

单元测试有助于代码的模块化,因此有助于长期的重用。因为有了测试,你就知道代码是可靠的,可以按照预期运行。从这个角度说,测试可以节省开发时间。单元测试的另一个好处是,有了测试,就等于就有了代码功能的文档,有助于其他开发者了解代码的意图。

单元测试应该避免依赖性问题,比如不存取数据库、不访问网络等等,而是使用工具虚拟出运行环境。这种虚拟使得测试成本最小化,不用花大力气搭建各种测试环境。

一般来说,单元测试的步骤如下。

  • 准备所有的测试条件
  • 调用(触发)索要测试的函数
  • 验证运行结果是否正确
  • 还原被修改的记录

2.2 其他测试类型

(1)集成测试

集成测试(Integration test)指的是多个部分在一起测试,比如测试一个数据库连接模块,是否能够连接数据库。

(2)功能测试

功能测试(Functional test)指的是,自动测试整个应用程序的某个功能,比如使用Seleniu木工锯自动打开浏览器运行程序。

(3)端对端测试

端对端测试(End-to-End testing)指的是全链路测试,即从开始端到终止端的测试,比如测试从用户界面、通过网络、经过应用程序处理、到达数据库,是否能够返回正确结果。端对端测试的目的是,确保整个系统能够正常运行,各个子系统之间依赖关系正常,数据能够在子系统之间、模块之间正确传递。

(4)冒烟测试

冒烟测试(smoke testing)指的是,正式的全面测试开始之前,对主要功能进行的预测试。它的主要目的是,确认主要功能能否满足需要,软件是否能运行。冒烟测试可以是手工测试,也可以是自动化测试。

这个名字最早来自对电子元件的测试,第一次电子元件通电,看看它是否会冒烟,如果没有冒烟,说明通过了测试;如果电流达到某个临界点之后,才出现冒烟,这时可以评估是否能够接受这个临界点。

3. 开发模式

测试不仅能够验证软件功能、保证代码质量,也能够影响软件开发的模式。

3.1 TDD模式

TDD是“测试驱动的开发”(Test-Driven Development)的简称,指的是先写好测试,然后再根据测试完成开发。使用这种开发方式,会有很高的测试覆盖率。

TDD的开发步骤如下。

  • 先写一个测试。
  • 写出最小数量的代码,使其能够通过测试。
  • 优化代码。
  • 重复前面散步。

TDD开发的测试覆盖率通常在90%以上,这意味着维护代码和新增特性会非常容易。因为测试保证了你可要信任这些代码,修改它们不会破坏其他代码的运行。

TDD接口提供以下四个方法。

  • suite()
  • test()
  • setup()
  • teardown()

下面代码是测试计数器是否加1。

suite('Counter', function () {
    test('tick increases count to 1', function () {
        var counter = new Counter();
        counter.tick();
        assert.equal(counter.count, 1)
    });
});

3.2 BDD

BDD是“行为驱动的开发”(Behavior-Driven Development)的简称,指的是写出优秀测试的最佳实践的总称。

BDD认为,不应该针对代码的实现细节写测试,而是针对行为写测试。BDD测试的是行为,即软件应该怎样运行。

BDD接口提供以下六个方法。

  • describe()
  • it()
  • before()
  • after()
  • beforeEach()
  • afterEach()

下面是测试计数器是否加1的BDD写法。

describe('Counter', function () {
    it('should increase count by 1 after calling tick', function () {
        var counter = new Counter();
        var expectedCount = counter.count + 1;
        counter.tick();
        assert.equal(counter.count, expectedCount);
    })
});

下面是一个BDD开发的示例。现在,需要开发一个==Foo==类,该类的实例有一个==sayHi==方法,会对类参数说“Hi”。这就是==Foo==类的规格,根据这个规格,我们可以写出测试用例文件==foo.spec.js==。

describe('Simple object', function () {
    var foo;
    
    beforeEach(function () {
        foo = new Foo('John');
    });
    
    it('should say hi', function () {
        expect(foo.sayHi()).toEqual('John says hi!');
    });
});

有了测试用例以后,我们再写出实际的脚本文件==foo.js。==

function Foo(name) {
    this.name = name;
}

Foo.prototype.sayHi = function () {
    return this.name + 'says hi!';
}

为了把测试用例与脚本文件分开,我们通常把测试用例放在==test==子目录之中。然后,我们就可以使用Mocha、Jasmine等测试框架,执行测试用例,看看脚本文件是否通过测试。

3.3 BDD术语

(1)测试套件

测试套件(test suite)指的是,一组针对软件规格的某个方面的测试用例。也可以看作,对软件的某个方面的描述(describe)。

测试套件由一个==describe==函数构成,它接受两个参数:第一个参数是字符串,表示测试套件的名字或标题,表示将要测试什么;第二个参数是函数,用来实现这个测试套件。

describe ('A suite', function () {
    // ...
});

(2)测试用例

测试用例(test case)指的是,针对软件一个功能点的测试,是软件测试的最基本单位。一组相关的测试用例,构成一个测试套件。测试用例由it函数构成,它与describe函数一样,接受两个参数:第一个参数是字符串,表示测试用例的标题,表示测试用例的标题;第二个参数是函数,用来实现这个测试用例。

describe ('A suite', function () {
    it('contains spec with an expectation', function () {
        // ...
    });
});

(3)断言

断言(assert)指的是对代码行为的预期。一个测试用例内部,包含一个或多个断言(assert)。

断言会返回一个布尔值,表示代码行为是否符合预期。测试用例之中,只要有一个断言为false,这个测试用例就会失败,只要所有断言都未true,测试用例才会通过。

describe('A suite', function () {
    it('contains spec with an expectation', function () {
        expect(true).toBe(true);
    });
});

4.断言

断言是判断实际值与预期值是否相等的工具。

断言有assert、expect、should三种风格,或者称为三种写法。

// assert风格
assert.equal(event.detail.item, '(item)');

// expect风格
expect(event.detail.item).to.equal('(item)');

// should风格
event.detail.item.should.equal('(item)');

Chai.js是一个很流行的断言库,同时支持上面三种风格。

(1)assert风格

var assert = require('chai').assert;
var foo = 'bar';
var beverages = {tea: ['chai', 'matcha', 'oolong']};

assert.typeOf(foo, 'string', 'foo is a string');
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');

上面代码中,assert方法的最后一个参数是错误提示信息,只有测试没有通过时,才会显示。

(2)expect风格

var expect = require('chai').expect;
var foo = 'bar';
var beverages = {tea: ['chai', 'matcha', 'oolong']};

expect(foo).to.be.a('string');
expect(foo).to.equal('bar');
expect(foo).to.have.length(3);
expect(beverages).to.have.property('tea').with.length(3);

(3)should风格

var should = require('chai').should();
var foo = 'bar';
var beverages = {tea: ['chai', 'matcha', 'oolong']}

foo.should.be.a('string');
foo.should.equal('bar');
foo.should.have.length(3);
beverages.should.have.property('tea').with.length(3);

预期的终极目标

以上内容不属于原创,只是整理的一些笔记。在之前的工作中,总会听到后端开发有个词叫单元测试,隐约觉得那是一种可以后台写代码自动测试自己的程序是否正确,觉得有点高大上,有点可望不可即。后来写vue项目,在官方文档中也看到这个词,觉得可能在不久的将来,前端为自己的程序编写类似的这种测试用例也是一种必备技能,就算不是专门去写node程序,可能以后面试vue,别人会问你有没有了解过vue里面的单元测试?有没有为自己的项目编写测试用例?

如何继续深入

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

推荐阅读更多精彩内容