组件库开发小记(二)组件单元测试
单元测试
安装
相关的安装教程直接阅读:教程 | Vue Test Utils
本组件库使用的测试框架为基于jest的vue测试框架,jest的方便之处用者皆知,整体而言比抹茶组合要舒服,但从使用上它们的差别并不大。
简单使用
同样以chatbox为例子:
describe("Chatbox.vue", () => {
it("renders props.text when passed", () => {
const props = {
text: ["你好", "你叫什么", "你喜欢我吗"],
};
const wrapper = shallowMount(component, {
propsData: props,
});
const textArrWrapper = wrapper.findAll(".ct-chatbox__msg");
for (let i = 0; i < textArrWrapper.length; i++) {
const text = textArrWrapper.at(i).text();
expect(text).toMatch(props.text[i]);
}
});
}
基本流程如下:
- 创建一个挂载后的组件,初始化其props
- 抽取组件的部分属性和值,如类名等特征
- 对抽取的属性和值进行校验
这里创建一个挂载组件的过程往往会在一个测试文件中大量重复因此,我们可以对其进行如下封装:
function createfactory(component) {
return ({ props = {}, data = {} }) => {
return shallowMount(component, {
propsData: props,
data() {
return {
...data,
};
},
});
};
}
在某个组件中进行测试时,只需要进行如下操作即可:
const factory = createfactory(Chatbox);
describe("", () => {
it("", () => {
const props = "xxx";
const wrapper = factory({props});
})
})
复杂使用
想要更好地进行测试则需要掌握更多的测试方法,下面再给出三种例子:
例子一:模拟点击一
场景很简单,即为模拟点击。
it("render closed when invoke clickHandler", (done) => {
const data = {
content: "你好",
};
const wrapper = factory({ data });
wrapper.vm.clickHandler();
Vue.nextTick(() => {
expect(wrapper.vm.isShow).toBeFalsy();
expect(wrapper.find(".modal-wrapper").exists()).toBeFalsy();
done();
});
});
如代码中的,通过wrapper.vm的点击函数来模拟点击效果,在点击过后对点击后的值进行确认。但是这里注册点击事件是异步的,其结果存入了下一个任务队列中,因此想获取其结果,需要借助Vue.nextTick来进行。
例子二:模拟点击二
该场景需要对上面的进行点击后的回调函数进行点击确认。
it("invoke callback when click confirm button", async () => {
const a = 1;
const data = {
content: "你好",
success: jest.fn(() => { a = 2;}),
};
const wrapper = factory({ data });
await wrapper.find(".confirm-btn").trigger("click");
expect(data.success).toHaveBeenCalled();
expect(a).toEqual(2);
});
如代码所示,回调函数传入了一个Mock的回调函数,它通过jest.fn()构造,只有这样的函数才能进行toHaveBeenCalled()判断。
如果仅仅想对函数是否点击进行确认,则采用空的jest.fn()来确认,而上面的回调中改变a变量的值的方法也是一种检测方式,但会增加复杂度。
另外,细心的你会发现,上面采用的async await的方式将解决了例子一中碰到的问题。
例子三:时间刺客
常常会有这样的测试场景,启动一个定时器,等待定时结束对结果进行判断,但是往往它会造成测试时间超时而报错或者浪费我们的等待时间。Jest提供了一个虚拟定时器的操作,能够进行时间加速(时间刺客)。
// global action for timers in this file
jest.useFakeTimers();
describe("Toast.vue", () => {
it("invoke method.close when ends", () => {
const data = {
content: "你好",
duration: 500,
};
const wrapper = factory({ data });
expect(wrapper.vm.closed).toBeFalsy();
// Accelerate time / Time fast-forward
setTimeout(() => {}, data.duration + 10);
jest.runAllTimers();
expect(wrapper.vm.closed).toBeTruthy();
});
});
根据jest的文档,需要在前面先使用jest.useFakeTimers();,而后面在启动定时器后便可以调用jest.runAllTimers();来加速时间,从而无需阻塞进程。