ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Karma+mocha+chai

2020-03-06 12:39:39  阅读:338  来源: 互联网

标签:function elm chai vm mocha Karma js Hello expect


三种工具简介

  1. Karma

    Karma官方网址
    Karma为前端自动化测试提供了跨浏览器测试的能力,可以自动在Chrome,Firefox,IE等主流浏览器依次跑完测试用例,同时也支持headless浏览器(入phantomJs)中运行测试用例。webpack+babel可以主动为想要适配的浏览器提供转码和垫片补丁引入能力,而Karma可以为最终的结果提供验证能力。Karma的配置方式可以阅读《webpack4.0各个击破(9)——Karma篇》进行了解。

  2. Mocha
    mocha是前端自动化测试框架,提供了不同风格断言库的兼容,测试用例分组,同步、异步测试架构,生命周期钩子等能力。

    基本用法

    describe('我现在要测某一个页面的几个功能',function(){
        describe('现在要测XX功能',function(){
            it('某个变量的值应该是数字',function(){
                //写断言
            })
        });
         describe('现在要测YY功能',function(){
            it('某个数组长度应该不小于10',function(){
                //写断言
            })
        });
    })
    

    异步测试

    describe('现在要测XX功能',function(){
        // done 传入done函数,在测试结束的时候调用,告知测试程序结束了,否则程序会等待超时
        it('异步请求应该返回一个对象', function(done){
    	  request
    	    .get('https://api.github.com')
    	    .end(function(err, res){
    	      expect(res).to.be.an('object');
    	      done();
    	    });
    	});
    	// promise的支持
    	it('异步请求应该返回一个对象', function() {
    	  return fetch('https://api.github.com')
    	    .then(function(res) {
    	      return res.json();
    	    }).then(function(json) {
    	      expect(json).to.be.an('object');
    	    });
    	});
    	// async await
        it('#async function', async () => {
    	    let r = await hello();
    	    assert.strictEqual(r, 15);
    	});
    });
    

    不同风格的断言库

    支持should.js,expect.js及node核心断言模块assert等。

    生命周期钩子

    describe('hooks', function() {
    
      before(function() {
        // 在本区块的所有测试用例之前执行
      });
    
      after(function() {
        // 在本区块的所有测试用例之后执行
      });
    
      beforeEach(function() {
        // 在本区块的每个测试用例之前执行
      });
    
      afterEach(function() {
        // 在本区块的每个测试用例之后执行
      });
    
      // test cases
    });
    

    生命周期钩子一般用来建立和清理环境或全局变量。

  3. chai
    Chai是一个断言库合集,支持expect,assert,should断言语法,非专业测试岗位其实没必要深究,了解使用方法就可以了。使用示例:

    expect(bar).to.not.exist;//断言变量bar不存在
    expect(data).to.have.ownProperty('length');//断言data有length属性
    expect(name).to.be.a('string');//断言name是一个字符串
    assert.equal(value1,value2);//断言value1和value2相等
    Tim.should.be.an.instanceof(Person);//断言Tim是Person类的实例
    

简单测试用例

// calculate.js
export default {
  add (a, b) {
    return a + b
  },
  minus (a, b) {
    return a - b - 1
  }
}


// calculate.spec.js
import calculate from '@/js/calculate'

describe('calculate test', () => {
  it('function add should return right sum', () => {
    expect(calculate.add(1, 2))
      .equal(3)
  })
  it('function minus should return right value', () => {
    expect(calculate.minus(2, 1)).equal(1)
  })
})

运行测试

// package.json
{
    "scripts": {
        "unit": "karma start karma.conf.js"
    }
}
===》 npm run unit

结果报告
在这里插入图片描述
与vue结合的测试

import Vue from 'vue' // 导入Vue用于生成Vue实例
import Hello from '@/components/Hello' // 导入组件
// 测试脚本里面应该包括一个或多个describe块,称为测试套件(test suite)
describe('Hello.vue', () => {
  // 每个describe块应该包括一个或多个it块,称为测试用例(test case)
  it('should render correct contents', () => {
    const Constructor = Vue.extend(Hello) // 获得Hello组件实例
    const vm = new Constructor().$mount() // 将组件挂在到DOM上
    //断言:DOM中class为hello的元素中的h1元素的文本内容为Welcome to Your Vue.js App
    expect(vm.$el.querySelector('.hello h1').textContent)
      .to.equal('Welcome to Your Vue.js App')  
  })
})

karma.conf.js的配置

var webpackConfig = require('../../build/webpack.test.conf')

module.exports = function (config) {
  config.set({
  	// 插件
  	plugins: [
      'karma-chrome-launcher',
      'karma-webpack',
      'karma-mocha',
      'karma-chai',
      'karma-spec-reporter',
      'karma-coverage'
    ],
    // 浏览器
    browsers: ['PhantomJS'],
    // 测试框架
    frameworks: ['mocha', 'sinon-chai', 'phantomjs-shim'],
    // 测试报告
    reporters: ['spec', 'coverage'],
    // 测试入口文件
    files: ['./index.js'],
    // 预处理器 karma-webpack
    preprocessors: {
      './index.js': ['webpack', 'sourcemap']
    },
    // Webpack配置
    webpack: webpackConfig,
    // Webpack中间件
    webpackMiddleware: {
      noInfo: true
    },
    // 测试覆盖率报告
    // https://github.com/karma-runner/karma-coverage/blob/master/docs/configuration.md
    coverageReporter: {
      dir: './coverage',
      reporters: [
        { type: 'lcov', subdir: '.' },
        { type: 'text-summary' }
      ]
    }
  })
}

util.js
从Vue官方的demo可以看出,对于Vue的单元测试我们需要将组件实例化为一个Vue实例,有时还需要挂载到DOM上,推荐Element的单元测试工具脚本Util.js,它封装了Vue单元测试中常用的方法

import Vue from 'vue'
import Element from 'element-ui'
Vue.use(Element)

let id = 0

const createElm = function () {
  const elm = document.createElement('div')

  elm.id = 'app' + ++id
  document.body.appendChild(elm)

  return elm
}

/**
 * 回收 vm
 * @param  {Object} vm
 */
exports.destroyVM = function (vm) {
  vm.$destroy && vm.$destroy()
  vm.$el &&
  vm.$el.parentNode &&
  vm.$el.parentNode.removeChild(vm.$el)
}

/**
 * 创建一个 Vue 的实例对象
 * @param  {Object|String}  Compo   组件配置,可直接传 template
 * @param  {Boolean=false} mounted 是否添加到 DOM 上
 * @return {Object} vm
 */
exports.createVue = function (Compo, mounted = false) {
  if (Object.prototype.toString.call(Compo) === '[object String]') {
    Compo = { template: Compo }
  }
  return new Vue(Compo).$mount(mounted === false ? null : createElm())
}

/**
 * 创建一个测试组件实例
 * @link http://vuejs.org/guide/unit-testing.html#Writing-Testable-Components
 * @param  {Object}  Compo          - 组件对象
 * @param  {Object}  propsData      - props 数据
 * @param  {Boolean=false} mounted  - 是否添加到 DOM 上
 * @return {Object} vm
 */
exports.createTest = function (Compo, propsData = {}, mounted = false) {
  if (propsData === true || propsData === false) {
    mounted = propsData
    propsData = {}
  }
  const elm = createElm()
  const Ctor = Vue.extend(Compo)
  return new Ctor({ propsData }).$mount(mounted === false ? null : elm)
}

/**
 * 触发一个事件
 * mouseenter, mouseleave, mouseover, keyup, change, click 等
 * @param  {Element} elm
 * @param  {String} name
 * @param  {*} opts
 */
exports.triggerEvent = function (elm, name, ...opts) {
  let eventName

  if (/^mouse|click/.test(name)) {
    eventName = 'MouseEvents'
  } else if (/^key/.test(name)) {
    eventName = 'KeyboardEvent'
  } else {
    eventName = 'HTMLEvents'
  }
  const evt = document.createEvent(eventName)

  evt.initEvent(name, ...opts)
  elm.dispatchEvent
    ? elm.dispatchEvent(evt)
    : elm.fireEvent('on' + name, evt)

  return elm
}

/**
 * 触发 “mouseup” 和 “mousedown” 事件
 * @param {Element} elm
 * @param {*} opts
 */
exports.triggerClick = function (elm, ...opts) {
  exports.triggerEvent(elm, 'mousedown', ...opts)
  exports.triggerEvent(elm, 'mouseup', ...opts)

  return elm
}

/**
 * 触发 keydown 事件
 * @param {Element} elm
 * @param {keyCode} int
 */
exports.triggerKeyDown = function (el, keyCode) {
  const evt = document.createEvent('Events')
  evt.initEvent('keydown', true, true)
  evt.keyCode = keyCode
  el.dispatchEvent(evt)
}

使用的例子

// Hello.vue
<template>
  <div class="hello">
    <h1 class="hello-title">{{ msg }}</h1>
    <h2 class="hello-content">{{ content }}</h2>
  </div>
</template>

<script>
export default {
  name: 'hello',
  props: {
    content: String
  },
  data () {
    return {
      msg: 'Welcome!'
    }
  }
}
</script>
// Hello.spec.js
import { destroyVM, createTest } from '../util'
import Hello from '@/components/Hello'

describe('Hello.vue', () => {
  let vm

  afterEach(() => {
    destroyVM(vm)
  })

  it('测试获取元素内容', () => {
    vm = createTest(Hello, { content: 'Hello World' }, true)
    expect(vm.$el.querySelector('.hello h1').textContent).to.equal('Welcome!')
    expect(vm.$el.querySelector('.hello h2').textContent).to.have.be.equal('Hello World')
  })

  it('测试获取Vue对象中数据', () => {
    vm = createTest(Hello, { content: 'Hello World' }, true)
    expect(vm.msg).to.equal('Welcome!')
    // Chai的语言链是无意义的,可以随便写。如下:
    expect(vm.content).which.have.to.be.that.equal('Hello World') 
  })

  it('测试获取DOM中是否存在某个class', () => {
    vm = createTest(Hello, { content: 'Hello World' }, true)
    expect(vm.$el.classList.contains('hello')).to.be.true
    const title = vm.$el.querySelector('.hello h1')
    expect(title.classList.contains('hello-title')).to.be.true
    const content = vm.$el.querySelector('.hello-content')
    expect(content.classList.contains('hello-content')).to.be.true
  })
})

测试结果:

Hello.vue
  √ 测试获取元素内容
  √ 测试获取Vue对象中数据
  √ 测试获取DOM中是否存在某个class

测试注意:
1、 测试脚本都要放在 test/unit/specs/ 目录下
2、 脚本命名方式为 [组件名].spec.js
3、所谓断言,就是对组件做一些操作,并预言产生的结果。如果测试结果与断言相同则测试通过
4、单元测试默认测试 src 目录下除了 main.js 之外的所有文件,可在 test/unit/index.js 文件中修改
5、Chai断言库中,to be been is that which and has have with at of same 这些语言链是没有意义的,只是便于理解而已

参考博客:
https://blog.51cto.com/13869008/2175983
https://www.jianshu.com/p/34afa645487b
https://blog.csdn.net/qq_34179086/article/details/89496825

标签:function,elm,chai,vm,mocha,Karma,js,Hello,expect
来源: https://blog.csdn.net/mnbcx123/article/details/104692110

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有