vue学习—单元测试


Jest 单元测试官网

vue-test-utils 单元测试官网



1. Jest 单元测试

Jest单元测试入门

jest快速入门及实践教程

  • 安装: npm i jest @types/jest

  • package.json 命令行: "test:unit": "jest --clearCache && vue-cli-service test:unit"

单元测试文件写在 test/unit 目录下

  • 常见命令:
{
  "nocache": "jest --no-cache", //清除缓存
  "watch": "jest --watchAll", //实时监听
  "coverage": "jest --coverage",  //生成覆盖测试文档
  "verbose": "npx jest --verbose" //显示测试描述
}
  • 默认会测试spec和test结尾的js文件,单元测试的文件名必须是xxxxxxxxx.spec.js或者xxxxxxxxx.test.js

  • 测试函数

test("测试用列描述信息",()=>{})
// or
it("测试用例描述信息",()=>{})
  • 断言函数
exspect(运行结果).toBe(期望的结果);
//常见断言方法
expect({a:1}).toBe({a:1})//判断两个对象是否相等
expect(1).not.toBe(2)//判断不等
expect({ a: 1, foo: { b: 2 } }).toEqual({ a: 1, foo: { b: 2 } })
expect(n).toBeNull(); //判断是否为null
expect(n).toBeUndefined(); //判断是否为undefined
expect(n).toBeDefined(); //判断结果与toBeUndefined相反
expect(n).toBeTruthy(); //判断结果为true
expect(n).toBeFalsy(); //判断结果为false
expect(value).toBeGreaterThan(3); //大于3
expect(value).toBeGreaterThanOrEqual(3.5); //大于等于3.5
expect(value).toBeLessThan(5); //小于5
expect(value).toBeLessThanOrEqual(4.5); //小于等于4.5
expect(value).toBeCloseTo(0.3); // 浮点数判断相等
expect('Christoph').toMatch(/stop/); //正则表达式判断
expect(['one','two']).toContain('one'); //不解释
  • 例子
import { param2Obj } from '@/utils/index.js'
describe('Utils:param2Obj', () => {
  const url = 'https://github.com/PanJiaChen/vue-element-admin?name=bill&age=29&sex=1&field=dGVzdA==&key=%E6%B5%8B%E8%AF%95'

  it('param2Obj test', () => {
    expect(param2Obj(url)).toEqual({
      name: 'bill',
      age: '29',
      sex: '1',
      field: window.btoa('test'),
      key: '测试'
    })
  })
})

it语法表示一个用例,expect表示预期结果,toBe表示三个等号的比较,如果条件成立单元测试即可通过。



2. Vue Test Utils

vue-test-utils 单元测试官网

安装: vue add @vue/unit-jest

  • 例子
import { shallowMount } from '@vue/test-utils'
import Hamburger from '@/components/Hamburger/index.vue'
describe('Hamburger.vue', () => {
  it('toggle click', () => {
    const wrapper = shallowMount(Hamburger)
    const mockFn = jest.fn()
    wrapper.vm.$on('toggleClick', mockFn)
    wrapper.find('.hamburger').trigger('click')
    expect(mockFn).toBeCalled()
  })
  it('prop isActive', () => {
    const wrapper = shallowMount(Hamburger)
    wrapper.setProps({ isActive: true })
    expect(wrapper.contains('.is-active')).toBe(true)
    wrapper.setProps({ isActive: false })
    expect(wrapper.contains('.is-active')).toBe(false)
  })
})


3. karma 单元测试

# 1, 初始化时,需要选择打开test功能,然后选择karma测试
vue init  webpack  testtodo 

# 2, 运行测试,test目录会出现coverage--icov-report--index.html 
# 浏览器打开这个index.html,可以查看所有的测试地方
npm run unit

# 3, 安装vue.js 官方的单元测试实用工具库
npm  install  --save-dev    @vue/test-utils@1.0.0-beta.12

mocha 是个测试框架,本身不带断言层,所以需要引进Chai 断言库实现单元测试
在这里插入图片描述

笔记总结
  • Util.js 方法包含了大多数Vue组件化的测试需求。

  • vm. e l v m . el vm. elvm.nextTick 和 vm. r e f 都 是 在 测 试 过 程 中 比 较 常 用 的 一 些 V u e 语 法 糖 。 需 要 注 意 : v m . ref 都是在测试过程中比较常用的一些Vue语法糖。 需要注意: vm. refVuevm.nextTick 方法是异步的,所以需要在里面使用done方法。

  • 异步断言,方法参数需要是 _ 或者 done

  • 大多数时候查询元素通过 querySelector 方法查询class获得
    vm.$el.querySelector(’.el-breadcrumb’).innerText

  • 大多数情况下查询是否存在某个Class通过 classList.contains 方法获得,查找的结果为 true 或 false

vm.$el .classList.contains(‘el-button–primary’)

  • 异步测试必须以 done() 方法结尾。setTimeout 和 vm.$nextTick 是常用的异步测试。

由于 Vue 进行异步更新 DOM 的情况,一些依赖 DOM 更新结果的断言必须在 vm.$nextTick() resolve 之后进行:

// 引用vue
import Vue from 'vue';
// 引用要测试的组件
import app from '../../src/app.vue';
// 描述要测试的内容
describe('test app.vue', () => {
    // 异步数据更新
    it('数据更新后,视图应该改变', done => {
        // 这里将app生成vue实例,并使用 $mount() 模拟挂载状态
        let vm = new Vue(app).$mount();
        // 挂载后改变title
        vm.title = 'APP';
        Vue.nextTick(() => {
            let title = vm.$el.getElementsByTagName('h1')[0]
            expect(title.textContent).toEqual('APP')
            done();
        })
    });
});
describe 的钩子(生命周期)
describe('hooks', function() {
  before(function() {
    // 在本区块的所有测试用例之前执行
  });
  after(function() {
    // 在本区块的所有测试用例之后执行
  });
  beforeEach(function() {
    // 在本区块的每个测试用例之前执行
  });
  afterEach(function() {
    // 在本区块的每个测试用例之后执行
  });
  // test cases
});
官方Demo的HelloWorld.spec.js代码
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')  
  })
})



4. 单元测试实例Demo代码

学习vue单元测试–视频

<template>
    <div>
        <section class="todoapp">
            <header class="header">
                <h1>todos</h1>
                <input  v-model="newtodo"  @keyup.enter="addtodo"  class="newtodo" autofocus autocomplete="off"
                placeholder="what needs to be done?" >
            </header>
            <section class="main" >
                <ul class="todo-list">
                    <li  v-for="todo in todos"   :key="todo.id"    class="todo"   >
                        <div class="view">
                            <label>{{todo.text}}</label>
                            <button  @click="deltodo(todo)"    class="destroy">删除</button>
                        </div>
                        <input  v-model="todo.text"   class="edit"  type="text"/>
                    </li>
                </ul>
            </section>
        </section>
    </div>                        
</template>

<script>
export default {
  name: 'todoMVC',
  data () {
    return {
      todos:[
          {    id:Math.random(),  text:"CSS"   },
          {    id:Math.random(),  text:"html"  }
      ],
      newtodo:''
    }
  },
  methods:{
    addtodo:function(){
      this.todos.push(
        {
        id: Math.random(),   
        text:this.newtodo
       }
      )
      this.newtodo=''
    },
    deltodo:function(todo){
      let index = this.todos.indexOf(todo);
      this.todos.splice(index,1)
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
html,body{
  margin: 0;
  padding: 0;
}
button {
  margin: 10px  30px;
  padding: 5px;
  border: 1px;
  background: rgb(126, 167, 126);
  font-size: 100%;
}
body{
  line-height: 1.4em;
}
</style>

在这里插入图片描述

todoMVC.spec.js 文件—测试用例
import {mount}  from '@vue/test-utils'
import todoMVC from '@/components/todoMVC'

// 创建测试套件
describe('HelloWorld.vue', () => {

  // 创建-- 查看 --测试用例
  it('测试查看功能', () => {
    // 通过mount 将组件渲染出来
    const wrapper = mount(todoMVC);
    // 寻找制定的dom元素
    console.log(wrapper.find('.todo-list'))   
    // 通过vm查看data中的某个数据
    console.log(wrapper.vm.todos)  
    // 断言
    expect(wrapper.vm.todos.length).to.be.equal(2)
  })

  // 创建-- 增加 --测试用例
  it('测试增加功能', () => {
    // 通过mount 将组件渲染出来
    const wrapper = mount(todoMVC);
    // 1, 对newtodo进行赋值
    wrapper.setData({newtodo: 'test-word'})   
    // 2,对new-todo触发回车事件
    wrapper.find('.newtodo').trigger('keyup.enter')  
    // 3,断言,检查todos中是否有数据增加
    expect(wrapper.vm.todos.length).to.be.equal(3)
    expect(wrapper.vm.todos[2].text).to.be.equal("test-word")
    console.log(wrapper.vm.todos)
  })

  // 创建-- 删除 --测试用例
  it('测试删除功能', () => {
    // 通过mount 将组件渲染出来
    const wrapper = mount(todoMVC);
    wrapper.find('.destroy').trigger('click')
    expect(wrapper.vm.todos.length).to.be.equal(1)
  })
})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值