# Vue项目中使用jest进行单元测试
# 1、背景
日常业务开发中,任务多,项目时间紧,产品和项目催得急,另外技术领导也并未强制要求编写单元测试,所以国内很大一部分程序员是不会去编写单元测试代码。我们团队也是(捂脸)。
最近在抽出业务中用到的组件,并单独剥离出来形成一个UI组件库;在参考学习业界优秀团队的开源组件库时,看到绝大部分开源组件库的单元测试覆盖率是非常高。因此,也在尝试编写一个组件,同时编写单元测试代码。
# 2、单元测试的含义
单元测试(模块测试)是开发者编写的一小段代码,用于检验被测代码的一个很小的、很明确的功能是否正确。通常而言,一个单元测试是用于判断某个特定条件(或者场景)下某个特定函数的行为。(源自百度百科)
# 3、Vue项目单元测试相关技术介绍
# jest
# jest是Vue官方放在最前面介绍的测试框架,由facebook出品。但是mocha也是一个非常优秀的测试框架。可以根据业务情况和团队来选择。
# Vue Test Utils
# Vue Test Utils 是 Vue.js 官方的单元测试实用工具库,提供更多详细的指引和自定义设置。
# 明白要测试的是什么
对于 UI 组件来说,我们不推荐一味追求行级覆盖率,因为它会导致我们过分关注组件的内部实现细节,从而导致琐碎的测试。
取而代之的是,我们推荐把测试撰写为断言你的组件的公共接口,并在一个黑盒内部处理它。一个简单的测试用例将会断言一些输入 (用户的交互或 prop 的改变) 提供给某组件之后是否导致预期结果 (渲染结果或触发自定义事件)。
# 4、撸起袖子就是干(编写单元测试)
# 第一步: 安装初始化一个项目
选择使用vue-cli3创建了一个项目,选择jest作为测试框架.
vue create vue-jest-test
- 新建项目test目录下有一个hello world组件单元测试示例文件,一起看一下
helloworld.spec.js
import {shallowMount} from '@vue/test-utils';
import HelloWorld from '@/components/HelloWorld.vue';
describe('HelloWorld.vue', () => {
it('renders props.msg when passed', () => {
const msg = 'new message';
const wrapper = shallowMount(HelloWorld, {
propsData: {msg}
});
expect(wrapper.text()).toMatch(msg)
});
});
# 第二步:新建一个card组件并编写单元测试
- components/card/index.vue```vue
<template>
<div class="card">
<div class="card-header" v-if="$slots.header">
<slot name="header"></slot>
</div>
<div class="card-body" v-if="$slots.body">
<slot name="body"></slot>
</div>
</div>
</template>
<script>
export default {
name: 'card',
props: {
},
created() {
console.log(this.$slots)
}
}
</script>
<style lang="scss" scoped>
.card {
border-radius: 12px;
background-color: #ffffff;
margin-bottom: 15px;
}
.card-header {
font-size: 19px;
color: #000000;
padding: 12px 15px;
}
.card-body {
padding:0 15px;
min-height: 60px;
}
</style>
- 在test目录下新建card目录card.spec.js
card目录下包含模拟的header内容和body内容
根据组件的设计需要测试的内容:
- 测试能否正常渲染card组件
- 测试传入slot=header的时候是否正常
- 测试传入slot=body的时候是否正常
card.spec.js具体代码
import {mount} from '@vue/test-utils'
import Card from '@/components/card/index.vue';
import CardHeader from './header';
import CardBody from './body';
describe('card.vue', () => {
it('renders empty card', () => {
const wrapper = mount(Card);
expect(wrapper.findAll('div')).toHaveLength(1);
});
it('renders pass a slot = header', () => {
const wrapper = mount(Card, {
slots: {
header: CardHeader, // 将匹配 `<slot name="header" />`。
}
});
expect(wrapper.find({name: 'header'}).is(CardHeader)).toBe(true);
});
it('renders pass a slot = body', () => {
const wrapper = mount(Card, {
slots: {
header: CardBody, // 将匹配 `<slot name="header" />`。
}
});
expect(wrapper.find({name: 'body'}).is(CardBody)).toBe(true);
})
});
- 运行单元测试
// 运行所有的单元测试文件
npm run test:unit
// 运行单个单元测试文件
npm run test:unit card/card.spec.js
运行成功后如下图
# 接入持续集成中
还可以接入集成化工具平台jenkins,gitlab-cli,travis-ci等。
在构建时配置单元测试命令运行单元测试,单元测试失败不允许进行下一步的操作。
参考资料