常用的测试框架有 Karma、mocha, 其中 Karma 是一个以浏览器为引擎的测试,而 mocha 用的是 Node.js, 淘宝推出了一个类 Karma 的开源框架叫 Totoro。
由于 Karma 是使用真实的浏览器环境,并且可以测试兼容性,我们采用 Karma 作为框架。
常用的断言库:
- Node.js 的 assert
- Jasmine
- expect
- Chai
和 Karma 比较配套的是 Jasmine。
npm i karma jasmine-core karma-jasmine karma-chrome-launcher -D
npm i karma -g
安装一个全局的 karma 命令,然后执行 karma init 生成 karrna.config.js
karma init
一路回车就好
然后新建一个 src 目录写源文件(src/util.js)
var util = {
reverse(str) {
return str
.split('')
.reverse()
.join('');
}
};
然后写测试文件(test/util-test.js)
describe('reverse', function() {
it('reverse word', function() {
expect(util.reverse('abc')).toEqual('cba');
});
});
接下来把文件添加到 karma.config.js 里面
module.exports = function(config) {
config.set({
...
// list of files / patterns to load in the browser
files: [
'test/*.js',
'src/*.js'
],
...
})
}
告诉它要在浏览器加载哪些文件,然后运行 karma start
执行测试,如果遇到报 karma 的模块找不到的情况,则可以把找不到的模块安装成全局的。
成功运行后,终端将会输出测试结果
浏览器也会打出结果
我们修改下代码再看下不通过的情况
describe('reverse', function() {
it('reverse word', function() {
expect(util.reverse('abc')).toEqual('abc');
});
});
这样就实现了一个最基本的单元测试,现在来看一下测试的覆盖率。
一般测试的覆盖率要越高越好,Karma 支持查看测试代码的覆盖率, 安装一个包:
npm install karma-coverage -D
然后在 karma.config.js 里面添加配置
preprocessors: {
'src/*.js': ['coverage']
},
// add
coverageReporter: {
type: 'html',
dir: 'coverage/'
},
reporters: ['progress', 'coverage'],
添加一个预处理,告诉它 src 下的源文件需要用 coverage 预处理一下,然后生成的 report 放在 coverage 目录下面,用 HTML 的形式。
重新运行 karma start
, 将会生成 HTML 文件,打开这个 HTML 文件就可以看到覆盖率报告。
覆蓝率为 100%, 我们给源 util 添加一个逻辑分支
var util = {
reverse(str) {
if (str.length <= 1) return str;
return str
.split('')
.reverse()
.join('');
}
};
然后再看覆盖率报告
可以看到,分支变成了 50%
再添加一个分支:
var util = {
reverse(str) {
if (typeof str !== 'string')
throw 'util.reverse should pass a string argument';
if (str.length <= 1) return str;
else
return str
.split('')
.reverse()
.join('');
}
};
点进 util 也可以看到哪些代码没有覆盖到:
在 util-test.js 里面添加测试代码
describe('reverse', function() {
it('reverse word', function() {
expect(util.reverse('abc')).toEqual('cba');
});
it('reverse字符串长度为1时返回自已', function() {
expect(util.reverse('a')).toBe('a');
});
it('reverse传值不是字符串时会抛异常', function() {
expect(function() {
util.reverse(null);
}).toThrow();
});
});
这时候看到覆盖率就成 100%了。
从浏览器加载的 util.js 中可以看到一段代码
可以看到总共被改成了 4 个分支,每个分支如果有执行就会顺带着执行 ++ 操作。这样它就可以统计到有多少代码被执行到了。
Jasmine 提供的断言 API 除了上面 toEqual/toBe/toThrow
之外, 具体还有
expect(result).toBeDefined();
expect(result).toBeGreaterThan(3);
expect(result).toBeLessThan(0);
expect(thing).toBeNaN();
expect(string).toContain(substring);
expect('my string').toMatch(/^my/);
自动化测试一般用 E2E 测试,即端到端测试。它的工具也有几种
- PhontomJS
- 无界面浏览器
- Senlenium
- 打开电脑的浏览器运行,支持多语言操控
- Protractor
- 是
Senlenium
的一个 JS 容器
- 是
我们使用 Protractor, 因为它提供了-些方便的操控浏览器的 API 以及断言库。
首先安装 protractor:
npm i protractor -g
webdriver-manager update
webdriver-manager start
然后写一个 conf.js
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['test-spec.js']
};
test-spec.js
describe('site', function() {
it('登录框正常使用', function() {
browser.waitForAngularEnabled(false);
browser.get('https://test.com');
expect(browser.getTitle()).toEqual('Search Listings in Las Vegas - tes');
$$('nav .sign-icon + li.sign-in').click();
expect($$('.sign-log').count()).toEqual(1);
$$('.sign-log input[name=account]').sendKeys('yin@abc.com');
$$('.sign-log input[name=password]').sendKeys('3345983893');
$$('.sign-log input[type=submit]').click();
browser.driver.sleep(1000);
expect($$('.sign-log').count()).toEqual(0);
});
});
我们测试登录框能否正常使用,先调 browser.get
打开一个网页,在 load 完成之后会继续执行下面的逻辑:先单击导航的 sign-in 弹出登录框,然后往两个输入框填入账号密码,再点提交按钮,让浏览器等待 1s, 最后检测弹框是否消失了。因为注册完会刷新页面。
然后运行 protractor start
, 它就会打开浏览器,自动打开网页,按照我们的设定执行。
首先看一下工程目录
- website
- karma.config.js
- unit-test
- index.js
- mock
- middleware.js
- home.js
- test
- sign-log-test.js
- util-test.js
- coverage
- html/index.html
- e2e-test
- conf.js
- spec
- test-login.js
要尽可能地提高覆盖率,并且测试要尽可能稳定,理想状态是多个版本迭代还能待续使用,每次上线前或者改完代码后都可以跑一下单元测试。对一些复杂、关键的操作使用自动化测试。
自动化测试写起来比较简单,就是比较烦琐。