对前端单元测试的一些记录
看了几篇觉得不错的文章,把有关单元测试的一些东西当笔记记录下来。
测试组件
这篇文章以jest和Vue Test Utils组合讲解了一个rating组件的测试。应该把组待测试的组件当成黑盒来看待,只测对外能访问到的东西,这样无论是改动代码实现还是未来有可能的重构都不会影响测试用例的执行。而一个组件对外能提供的功能就是prop和用户操作,所以要测这两部分。
这个rating组件应该有很多功能,就挑两个比较有代表性的功能:
- 在
star
prop传入后,小于等于这个index的星星应该有active
的css类 - 用户点击一个星星的时候,应该会切换该星星和下一个星星的
active
类
// Rating.spec.js
beforeEach(() =>
(wrapper = shallowMount(Rating, { propsData: { maxStars: 6, grade: 3 } })))
afterEach(() => wrapper.destroy())
describe('Rating', () => {
it('renders a list of stars with class `active` equal to prop.grade', () => {
expect(wrapper.findAll('.active').length).toEqual(3)
})
it('adds `active` class on an inactive star when the user clicks it', () => {
const fourthStar = wrapper.findAll('[data-test-id="star"]').at(3)
fourthStar.trigger('click')
expect(fourthStar.classes()).toContain('active')
})
})
值得一提的是,为了让样式和测试代码完全解耦,作者在后面用自定义指令代替了对CSS类的断言,为此还修改了NODE_ENV
的值以专门将指令用于测试环境。但我看Element UI采用的是.el-rate__icon
这种类似命名空间的类名定义,应该是一开始就定义规划好了,所以用自定义指令这部分就没细看了。
测试API
这篇文章用jest模拟了axios模块,使之能不修改源码、不消耗网络资源对代码进行测试。
文章假设有一个接口可以返回专辑的信息,待测函数去拿这个接口,并返回第一张专辑的标题,最终的代码是这样的
// index.test.js
const getFirstAlbumTitle = require("./index");
const axios = require("axios");
jest.mock("axios");
it("returns the title of the first album", async () => {
axios.get.mockResolvedValue({
data: [
{
userId: 1,
id: 1,
title: "My First Album",
},
{
userId: 1,
id: 2,
title: "Album: The Sequel",
},
],
});
const title = await getFirstAlbumTitle();
expect(title).toEqual("My First Album");
});
先加载待模拟的模块,通过jest.mock()
对整个模块进行模拟,这时候在测试环境下哪里访问这个模块下的函数都会被模拟,然后通过mockResolvedValue
这个方法返回一个promise的resolve方法,在上面的代码里可以看到直接输出了一个假结果。在这篇文章的另外一个网站,有评论指出要在每个测试后执行jest.resetAllMocks()
来重置模拟,这样就不会影响到其他测试的执行。
因为上面例子的返回值是硬编码到测试用例中的,如果有很多测试想用到这种假数据,可以用手动模拟