测试框架
目前基于 vue 项目框架采用 vue-jest
文件组织结构
- 全局通用的配置
统一放在 test/setup.ts ,结合 jest.config 配置 setupFiles: ['./src/test/setup.ts']
示例:
import { config } from '@vue/test-utils'
config.global.mocks = { $ossPath: '' }
- api 的 mock 数据
文件以mocks命名,放在对应 api 文件下 ,jest 会自动识别这个文件,在测试文件中按正常 api 调用的写法即可。
- 测试文件
文件以tests命名,放在对应需要测试的文件下
cicd 流程
在.gitlab-ci.yml 文件中加入测试流程,每一次发布都要跑单元测试,代码以模组为例:
stages:
- autochart
- detect
- test
- build
- deploy
...
test:unit-test:
stage: test
image: ${CI_IMAGE_NODE}
only:
- master
- tags
extends: .node-cache
script:
- yarn run test --silent
tags:
- ali
- docker
- new
代码规范
目前采用 eslint-plugin-jest( https://github.com/jest-community/eslint-plugin-jest#readme )
不需要测试
- 第三方提供的功能
- antdesign 中的组件、vue-router 的路由跳转方法
- 与逻辑无关的 UI
- 布局、样式
示例
一个单元测试的结构
describe('一类测试', () => {
let wrapper: Wrapper<Vue>
beforeEach(() => {
wrapper = shallowMount(component, {})
})
afterEach(() => {
wrapper.destroy()
})
it('测试一', () => {
expect().toBeTruthy()
})
it('测试二', () => {
expect().toBeTruthy()
})
})
异步 expect
import { nextTick } from 'vue'
const asyncExpect = (fn: () => void) => {
return new Promise(resolve => {
nextTick(() => {
fn()
resolve(0)
})
})
}
describe('aa', () => {
it('aaa', async() => {
...
// await wrapper.vm.$nextTick()
// expect(getOrderInfo).toBeCalledTimes(3)
// expect(wrapper.vm.orderStatus).toBe(3)
await asyncExpect(() => {
expect(getOrderInfo).toBeCalledTimes(3)
expect(wrapper.vm.orderStatus).toBe(3)
})
})
})
自定义匹配——可以抽取出一些相同结构的 matchers
expect.extend({
innerHtmlToBe(ele, str) {
const pass = ele.element.innerHTML === str
if (pass) {
return {
message: () => 'success',
pass: true
}
} else {
return {
message: () => 'fail',
pass: false
}
}
}
})
describe('AlertTest', () => {
test('设置title时,能正确显示title', async () => {
const wrapper = shallowMount(Alert, {
props: {
title: 'aa'
}
})
// expect(wrapper.find('.alert-title').element.innerHTML).toBe('aa')
expect(wrapper.find('.alert-title')).innerHtmlToBe('aa')
})
})
ts 中需要同步配置该 matchers 类型
namespace jest {
interface Matchers<R> {
innerHtmlToBe(s: string): R
}
}