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

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

作者: littleyu | 来源:发表于2018-12-10 14:25 被阅读23次

    测试库: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 任务状态改变(失败或成功)都会向你的邮箱里发一封邮件,所以我们并不用一直打开他的网页

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/zspthqtx.html