测试库:chai

1
2
3
4
5
// 安装
npm i -D chai

// 引入
import {expect} from 'chai'

打包工具:parcel

1
2
3
4
5
// 安装
npm i -D parcel

// 只需一行代码即可打包,不需要任何配置
parcel index.html --no-cache

测试刚在 vue 写按钮组件

🌰:一个简单的轮子
button.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<template>
<button @click="$emit('click')">
<svg class="icon" aria-hidden="true">
<use :xlink:href="`#icon-${icon}`"></use>
</svg>
<slot></slot>
</button>
</template>
<script>
export default {
props: ['icon'],
name: 'Button'
}
</script>
<style lang="scss">
.icon {
width: 1em;
height: 1em;
}
button {
padding: 10px 20px;
font-size: 14px;
}
</style>

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<g-button @click="click" icon="settings">这是一个按钮</g-button>
</div>
<div id="div"></div>
<script src="./src/index.js"></script>
<!-- <script src="./node_modules/vue/dist/vue.min.js"></script> -->
<!-- <script src="./button.js"></script> -->
<!-- <script>
new Vue({
el: '#app'
})
</script> -->
</body>
</html>

单元测试

开始第一次单元测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import Vue from 'vue'
import Button from './button'
import {expect} from 'chai'

Vue.component('g-button', Button)
new Vue({
el: '#app'
})

{
const vm = Vue.extend(Button)
const button = new vm({
el: '#div',
propsData: {
icon: 'settings'
}
})
const icon = button.$el.querySelector('use')
console.log(icon)
expect(icon.getAttribute('xlink:href')).to.eq('settings'); // 断言语句。
}

失败

第一次测试失败,svg属性没写全

所以再试一次~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import Vue from 'vue'
import Button from './button'
import {expect} from 'chai'

Vue.component('g-button', Button)
new Vue({
el: '#app'
})

{
const vm = Vue.extend(Button)
const button = new vm({
el: '#div',
propsData: {
icon: 'settings'
}
})
const icon = button.$el.querySelector('use')
console.log(icon)
expect(icon.getAttribute('xlink:href')).to.eq('#icon-settings'); // 断言语句。
}

成功

成功啦~,
浏览器中没有任何报错说明测试通过

但是每次都打开浏览器、刷新,实在是非常麻烦,所以我们再继续自动化测试

自动化测试

工具:

  1. Karma(卡玛)是一个测试运行器,它可以呼起浏览器,加载测试脚本,然后运行测试用例
  2. Mocha(摩卡)是一个单元测试框架/库,它可以用来写测试用例
  3. Sinon(西农)是一个spy / stub / mock 库,用以辅助测试(使用后才能理解)

then:

1
2
3
// 安装各种工具
// npm i -D karma karma-chrome-launcher karma-mocha karma-sinon-chai mocha sinon sinon-chai karma-chai karma-chai-spies // 最新npm包,防止版本报错,建议锁定版本
npm i -D karma@2.0.4 karma-chrome-launcher@2.2.0 karma-mocha@1.3.0 karma-sinon-chai@1.3.4 mocha@5.2.0 sinon@6.0.1 sinon-chai@3.2.0 karma-chai@0.1.0 karma-chai-spies@0.1.4

创建 Karma 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 新建 karma.conf.js,内容如下
module.exports = function (config) {
config.set({
// base path that will be used to resolve all patterns (eg.files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['mocha', 'sinon-chai'],
client: {
chai: {
includeStack: true
}
},
// list of files / patterns to load in the browser
files: [
'dist/**/*.test.js',
'dist/**/*.test.css'
],
// list of files / patterns to exclude
exclude: [],
// preprocess matching files before serving them to the browser
// available preprocessors: https//npmjs.org/browse/keyword/karma-reporter
preprocessors: {},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level if logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: http://npmjs.org/browse/keyword/karma-launcher
browsers: ['Chrome'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false,
// Concurrenecy level
// how many browser should be started simultaneous
concurrency: Infinity
})
}

创建test目录并在其目录下创建并更改 button.test.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// import {expect} from 'chai'
const expect = chai.expect
import Vue from 'vue'
import Button from '../src/button'

Vue.config.productionTip = false
Vue.config.devtools = false

describe('Button', () => {
it('存在', () => {
expect(Button).to.be.ok //不是 undefined null 0 '' 等falsy值
})
it('可以设置icon', () => {
const vm = Vue.extend(Button)
const button = new vm({
el: '#div',
propsData: {
icon: 'settings'
}
})
const icon = button.$el.querySelector('use')
console.log(icon)
expect(icon.getAttribute('xlink:href')).to.equal('#icon-setting')
})
it('点击 button 触发 click 事件', () => {
const vm = Vue.extend(Button)
const button = new vm({
el: '#div',
propsData: {
icon: 'settings'
}
})
const callback = sinon.fake()
button.$on('click', callback)
button.$el.click()
expect(callback).to.have.been.called
})
})

创建测试脚本
package.json 里面找到 script 并改写里面的内容

1
2
3
4
"scripts": {
"dev-test": "parcel watch test/* --no-cache & karma start",
"test": "parcel build test/* --no-cache --no-minify & karma start --single-run"
}

准备完毕,开始跑我们的代码

1
2
3
// 这行命令会自动打开浏览器并测试
npm run test
// 或者 npm run dev-test // 持续打包

当用例全部成功时:

成功~

当有用例失败时,终端会提示报错:

失败

更多测试语句请参考 chai官方API

中途遇到的报错~

package.json 添加如下:

1
2
3
"alias": {
"vue": "./node_modules/vue/dist/vue.common.js"
}

持续集成

说到懒,一向是程序员的优良传统~

目前比较流行的是 TravisCi(免费) 和 circleCi(收费,功能强大)

阮一峰的Travis教程

首先我们继续在根目录创建文件 .travis.yml

内容如下:

1
2
3
4
5
6
7
8
9
10
11
language: node_js # 使用node_js进行测试
node_js: # node_js版本号
- "8"
- "9"
- "10"
addons: # 插件
chrome: stable # 谷歌浏览器稳定版
sudo: required
before_script:
- "sudo chown root /opt/google/chrome/chrome-sandbox"
- "sudo chmod 4755 /opt/google/chrome/chrome-sandbox"

then:
我们前去 Travis 官方网站,并使用 GitHub 帐号关联登陆,并找到刚刚的测试项目,然后开启

返回首页,我们就能看到已经在测试啦~

开始啦

但是,我们又报错了 =。=

error

报错并不可怕,翻来覆去只能想到返回 Karma 的配置,改一下浏览器设置

1
2
3
// start these browsers
// available browser launchers: http://npmjs.org/browse/keyword/karma-launcher
browsers: ['ChromeHeadless'],

由于我们接入了 GitHub 所以,在我们提交之后, Travis 就会检测到文件改变并自动测试~

当 Travis 任务状态改变(失败或成功)都会向你的邮箱里发一封邮件,所以我们并不用一直打开他的网页