尝试写第一个单元测试、自动化测试、持续集成2018-12-07

测试库:chai

// 安装
npm i -D chai

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

打包工具:parcel

// 安装
npm i -D parcel

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

测试刚在 vue 写按钮组件

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

<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

<!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>

单元测试

开始第一次单元测试

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属性没写全

所以再试一次~

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:

// 安装各种工具
// 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 配置

// 新建 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

// 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 并改写里面的内容

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

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

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

当用例全部成功时:

成功~

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

失败

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


-
-
-
-
-
-
-

中途遇到的报错~

image.png

package.json 添加如下:

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

持续集成

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

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

阮一峰的Travis教程

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

内容如下:

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 的配置,改一下浏览器设置

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

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

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

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

推荐阅读更多精彩内容