《自动化测试》

415 阅读7分钟

之前我们做单元测试,自己在app.js里写测试用例,但是每次都需要刷新浏览器。能不能有一种方法,能运行一句代码后,就自动唤起浏览器,自动运行测试用例呢

于是我们使用 Karma + Mocha做单元测试

一. 实现自动打开浏览器测试

Karma([ˈkɑrmə] 卡玛)是一个测试运行器,它可以呼起浏览器,加载测试脚本,然后运行测试用例

Mocha([ˈmoʊkə] 摩卡)是一个单元测试框架/库,它可以用来写测试用例

步骤

1. 安装各种工具

npm i -D karma karma-chrome-launcher karma-mocha karma-sinon-chai mocha sinon sinon-chai karma-chai karma-chai-spies

2. 创建 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-preprocessor
            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 of 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: https://npmjs.org/browse/keyword/karma-launcher
            browsers: ['ChromeHeadless'],

            // Continuous Integration mode
            // if true, Karma captures browsers, runs the tests and exits
            singleRun: false,

            // Concurrency level
            // how many browser should be started simultaneous
            concurrency: Infinity
        })
}

3. 创建 test/button.test.js 文件

 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
     })
     it('可以设置icon.', () => {
         const Constructor = Vue.extend(Button)
         const vm = new Constructor({
         propsData: {
             icon: 'settings'
         }
         }).$mount()
         const useElement = vm.$el.querySelector('use')
         expect(useElement.getAttribute('xlink:href')).to.equal('#i-settings')
         vm.$destroy()
     })
     it('可以设置loading.', () => {
         const Constructor = Vue.extend(Button)
         const vm = new Constructor({
         propsData: {
             icon: 'settings',
             loading: true
         }
         }).$mount()
         const useElements = vm.$el.querySelectorAll('use')
         expect(useElements.length).to.equal(1)
         expect(useElements[0].getAttribute('xlink:href')).to.equal('#i-loading')
         vm.$destroy()
     })
     it('icon 默认的 order 是 1', () => {
         const div = document.createElement('div')
         document.body.appendChild(div)
         const Constructor = Vue.extend(Button)
         const vm = new Constructor({
         propsData: {
             icon: 'settings',
         }
         }).$mount(div)
         const icon = vm.$el.querySelector('svg')
         expect(getComputedStyle(icon).order).to.eq('1')
         vm.$el.remove()
         vm.$destroy()
     })
     it('设置 iconPosition 可以改变 order', () => {
         const div = document.createElement('div')
         document.body.appendChild(div)
         const Constructor = Vue.extend(Button)
         const vm = new Constructor({
         propsData: {
             icon: 'settings',
             iconPosition: 'right'
         }
         }).$mount(div)
         const icon = vm.$el.querySelector('svg')
         expect(getComputedStyle(icon).order).to.eq('2')
         vm.$el.remove()
         vm.$destroy()
     })
     it('点击 button 触发 click 事件', () => {
         const Constructor = Vue.extend(Button)
         const vm = new Constructor({
         propsData: {
             icon: 'settings',
         }
         }).$mount()

         const callback = sinon.fake();
         vm.$on('click', callback)
         vm.$el.click()
         expect(callback).to.have.been.called

     })
 })

4. 创建测试脚本

在 package.json 里面找到 scripts 并改写 scripts

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

5. 运行测试脚本

可以使用npm run test ,他会先把test目录下的所有文件打包,然后不缓存。成功以后,开启karma,只运行一次。

这种情况下,我们每次修改代码,想再次测试,就要重新运行npm run test 一次,能不能让我在修改代码后,就能自动测试呢?

使用npm run dev-test ,但是windows上会报错,分着输入命令:新开一个 Git Bash 窗口运行 npx parcel watch test/* --no-cache 再开一个 Git Bash 窗口运行 npx karma start。这样一来,只需要在一开始输入这两句命令,之后只要修改代码,就能自动测试了。

二. 使用travisci 持续集成

之前我们使用npm run dev-test 能实现一句代码,自动测试。能不能再自动化一点,让我们不需要输入命令,就能自动测试呢?

可以持续集成。使用travisci。前提是在项目的根目录下边,新建一个.travis.yml文件,写入一下内容:

language: node_js
node_js:
  - "8"
addons:
  chrome: stable
sudo: required
before_script:
  - "sudo chown root /opt/google/chrome/chrome-sandbox"
  - "sudo chmod 4755 /opt/google/chrome/chrome-sandbox"

然后,登录travisci官网,选择要进行持续集成的项目。

然后把当前代码提交,push到github,在travisci那里就能自动测试。

之后如果修改了代码,只要把代码push到github上,travisci就能自动进行测试,检查有没有错误,这就是持续集成

三. 发布自己的npm包,给别人用

我们使用别人的包,要通过npm下载。那想把自己的代码给别人用,就要把自己的代码上传到npm,让别人通过npm下载。

步骤:

  1. 确保所有代码都测试通过

    npm run test 全部是绿色才行。

  2. 上传代码到 npmjs.org

首先更新 package.json:

在 package.json 里将版本号改为 0.0.1,等全都做完了再改成 1.0.0

根目录下创建 index.js,在 index.js 里将你想要导出的内容全部导出(想让别人用的东西),比如我们现在只写了三个按钮,那就导出这三个按钮。

import Button from "./src/Button";
import ButtonGroup from "./src/ButtonGroup";
import Icon from "./src/Icon";
export {Button,ButtonGroup,Icon}
这个index.js就是package.json文件里的入口文件,即`main`选项后边的就写`index.js`

去官网 www.npmjs.com/ 注册一个账户,注册后会给我们发邮件,必须打开一下,之后才能发布。

在 要发布的项目根目录运行 npm adduser ,逐步填写用户名,密码,邮箱。

如果错误提示里面含有 registry.npm.taobao.org 则说明我们的 npm 源目前为淘宝源,需要更换为 npm 官方源才行。怎么换呢?先运行npm config list ,会看到配置选项, 发现很多都是淘宝源,我们只需要修改带有registry这个字段的,找它所在的路径,在我这里就是C:\Users\18742\.npmrc 这个文件,打开这个文件,把registry = "https://registry.npm.taobao.org/" 这一句注释掉,保存。现在就不是淘宝源了。

然后重新npm adduser ,逐步填写用户名,密码,邮箱。此时应该正常了,会显示:正确的官方源:

  1. 运行 npm publish 发布(之前要把所有代码提交,push)。如果成功,会显示: 然后别人通过npm i my_wheel 就可以安装我们发布的包了。

成功发布之后,就可以回去再把npm源改成淘宝源,为了以后安装其他包速度快一点(注释去掉)。以后就发布之前用官方源,之后改回淘宝源

假装别人使用自己的包

在桌面建一个tmp目录,在这个目录下安装我们的包:npm i my_wheel ,安装成功后,看到项目结构变成了这样:其实这里并不需要上传我们的所有代码,有一些是可以废弃的。

我们的包是一个Vue的UI框架,所以猜测用户会使用vue-cli 使用我们的包。那我们就假装在使用vue-cli的情况下,看看是否能成功使用我们的包。

去vue-cli 的官网,照着步骤搭建一个项目,

npm install -g @vue/cli
vue create hello-world
cd hello-world
npm run serve

就能用浏览器打开,看到一个最基本的页面。 然后怎么在hello-world这个里用我们的包呢?当然是进入这个目录,npm i my_wheel 安装。安装好了以后,试试能不能用:在用户的入口文件main.js里

import {Button,ButtonGroup,Icon} from 'my_wheel'

console.log(Button)
console.log(ButtonGroup);
console.log(Icon);

发现浏览器报错了:这是因为我们导出这个包的时候是在index.js里用export语法导出别人要用的东西,所以就需要使用import语法导入。但是问题就在于,目前node还不支持import语法。

解决: 用 babel 转译 import。转译好了再给别人用。

在我们的轮子项目里:

  1. npx parcel build index.js --no-minify (本来不应该加 --no-minify 的,奈何不加会有 bug,HTML 压缩把 slot 标签全删了)。它会生成dist目录下的三个文件:
  2. 将 package.json 的 main 改为 dist/index.js,即导出dist里的index.js,因为只有这个才是转译过的

然后重新npm publish 发布包,注意版本号要变,不能是上一个

然后切换回用户,再次安装这个包,它会自动下载最新的版本。

发现可以正确打印引入的对象了: 然后使用这些组件:

<template>
  <div id="app">
    <Button>我是一个按钮</Button>
  </div>
</template>

<script>

import {Button} from 'my_wheel'

export default {
  name: 'App',
  components: {
    Button
  }
}
</script>

用户可以成功使用了!

npm link 简化发布过程

现在我们每修改一次源代码,就要更新pacjage.json里的版本号,npm publish上传一次,然后为了测试是否好用,用户就要随之再下载更新一次。能不能加快这个效率呢?

有一种方法,用于本机上测试的高效的做法: 修改代码后,在项目目录使用 npm link,然后为了自己测试能不能用,在本机上,在使用之处运行 npm link my_wheel,就是最新了

如果使用yarn,就把npm 都换成yarn 就行了。