一、渲染: mount 和 shallowMount
1.1
mount
和
shallowMount
vue-test-utils
提供了两种方式用于渲染,或者说 加载(mount) 一个组件 —
mount
和
shallowMount
。一个组件无论使用这两种方法的哪个都会返回一个
wrapper
,也就是一个包含了
Vue 组件
的对象,辅以一些对测试有用的方法。
1.2
mount
和
shallowMount
的区别
mount
: 会渲染子组件shallowMount
:会加载子组件,不会被子组件的行为属性影响该组件
二、 beforeEach 和beforeAll
2.1 为多次测试重复设置
如果你有一些要为多次测试重复设置的工作,可以使用beforeEach和afterEach。
有这样一个需求,需要我们在每个测试之前调用方法initializeCityDatabase(),在每个测试后,调用方法clearCityDatabase()
beforeEach(()=>{initializeCityDatabase();});afterEach(()=>{clearCityDatabase();});test('city database has Vienna',()=>{expect(isCity('Vienna')).toBeTruthy();});test('city database has San Juan',()=>{expect(isCity('San Juan')).toBeTruthy();});
2.2 一次性设置
在某些情况下,你只需要在文件的开头做一次设置。这种设置是异步行为的时候,你不太可能一行处理它。Jest提供了beforeAll和afterAll处理这种情况。
beforeAll(()=>{returninitializeCityDatabase();});afterAll(()=>{returnclearCityDatabase();});test('city database has Vienna',()=>{expect(isCity('Vienna')).toBeTruthy();});test('city database has San Juan',()=>{expect(isCity('San Juan')).toBeTruthy();});
2.3 作用域
默认情况下,before和after的块可以应用到文件中的每一个测试。此外可以通过describe块来将将测试中的某一块进行分组。当before和after的块在describe块内部的时候,则只适用于该describe块内的测试。
三、匹配器
3.1 匹配器基础
toBe
:判断是否相等toBeNull
:判断是否为nulltoBeUndefined
:判断是否为undefinedtoBeDefined
:与上相反toBeNaN
:判断是否为NaNtoBeTruthy
:判断是否为truetoBeFalsy
:判断是否为falsetoContain
:数组用,检测是否包含toHaveLength
:数组用,检测数组长度toEqual
:对象用,检测是否相等toStrictEqual
:功能与 toEqual 相似,但是更加严格toThrow
:异常匹配toBeCalled
: 函数是否被调用toHaveBeenCalledTimes
: 函数被调用几次expect.assertions(n)
: 表示必须执行n次expect 代码才算执行完
3.2 匹配器使用
describe('Test',()=>{// 判断是否相等expect(2+2).toBe(4);// 判断是否为nullexpect(null).toBeNull();// 判断是否为undefinedexpect(undefined).toBeUndefined();let a =1;// 判断是否不为undefinedexpect(a).toBeDefined();
a ='ada';// 判断是否为NaNexpect(a).toBeNaN();
a =true;// 判断是否为trueexpect(a).toBeTruthy();
a =false;// 判断是否为falseexpect(a).toBeFalsy();
a =[1,2,3];// 数组用,检测是否包含expect(a).toContain(2);// 数组用,检测数组长度expect(a).toHaveLength(3);
a ={a:1};// 对象用,检测是否相等expect(a).toEqual({a:1});// 功能与 toEqual 相似,但是更加严格expect(a).toStrictEqual({a:1});a=()=>1;// 函数是否被调用expect(a).toBeCalled();// 函数被调用几次expect(a).toHaveBeenCalledTimes(1);});
3.3
toStrictEqual
与
toEqual
的区别
toStrictEqual 的功能与 toEqual 相似,但是更加严格。主要体现在:
- 即使两个对象的成员相同,但原型链不同则不同。
- undefined 和未定义不兼容。
3.4 expect.assertions(number)
验证在测试期间调用了一定数量的断言,在测试异步代码时这通常很有用,以便确保回调中的断言确实被调用。
假设我们有一个函数doAsync,它接收两个回调callback1和callback2,它将异步地以一个未知的顺序调用它们。
test('doAsync calls both callbacks',()=>{
expect.assertions(2);functioncallback1(data){expect(data).toBeTruthy();}functioncallback2(data){expect(data).toBeTruthy();}doAsync(callback1, callback2);});
四、Wrapper
Wrapper
:Wrapper 是一个包括了一个挂载组件或 vnode,以及测试该组件或 vnode 的方法。Wrapper.vm
:这是该 Vue 实例。你可以通过 wrapper.vm 访问一个实例所有的方法和属性。Wrapper.classes
:返回是否拥有该class的dom或者类名数组。Wrapper.find
:返回第一个满足条件的dom。Wrapper.findAll
:返回所有满足条件的dom。Wrapper.html
:返回html字符串。Wrapper.text
:返回内容字符串。Wrapper.setData
:设置该组件的初始data数据。Wrapper.setProps
:设置该组件的初始props数据。Wrapper.trigger
:用来触发事件。
五、模拟函数
5.1 模拟函数
jest.fn()
:生成一个模拟函数,这个函数可以用来代替源代码中被使用的第三方函数mockFn.mockImplementation(fn)
:接受一个函数,该函数应用作模拟的实现mockFn.mockImplementationOnce(fn)
:接受一个函数,该函数将用作对被模拟函数的一次调用的模拟实现mockFn.mockReturnValue(value)
:用于定义在指定函数的每一次调用时返回预设值mockFn.mockReturnValueOnce(value)
:mockFn.mockResolvedValue(value)
:用于定义在指定异步
函数的每一次调用时返回预设值mockFn.mockResolvedValueOnce(value)
:
5.2 mockImplementationOnce()
const myMockFn = jest.fn(()=>'default').mockImplementationOnce(()=>'first call').mockImplementationOnce(()=>'second call');
console.log(myMockFn(),myMockFn(),myMockFn(),myMockFn());// 'first call', 'second call', 'default', 'default'
六、mock系统
6.1 常用的mock方法
在单元测试中,很多时候不想因为通过测试而改变原来的代码逻辑或者只是想简单地获取一个数据来顺利进行测试,这个时候就需要手动mock数据,Jest提供了一个强大的mock系统。在全局的Jest对象里,有三个常用的mock方法:
jest.fn(implementation)
:返回一个mock函数,其中implementation 为可选,代表mock函数的模拟实现。jest.mock(moduleName, factory, options)
:用来mock一些模块或者文件。jest.spyOn(object, methodName)
:返回一个mock函数,和jest.fn相似,但是能够追踪object[methodName]的调用信息,如果object[methodName]不是一个函数,则会报错。
6.2 jest.fn()
Jest.fn()是创建Mock函数最简单的方式,如果没有定义函数内部的实现,jest.fn()会返回undefined作为返回值。
Jest.fn()所创建的Mock函数还可以设置返回值,定义内部实现或返回Promise对象。
6.3 jest.mock()
6.3.1 使用 jest.mock 自动 mock
jest.mock('./utils.ts')
自动返回一个 mock ,可以使用它来监视对类构造函数及其
所有方法
的调用。
6.3.2 jest.mock()直接在单元测试里面mock 模块
jest.mock(path, moduleFactory)
接受模块工厂参数。模块工厂是一个返回模拟的函数。为了模拟构造函数,模块工厂必须返回构造函数。换句话说,模块工厂必须是返回函数的函数-高阶函数(HOF)。
jest.mock('fs',()=>({readFileSync: jest.fn()}))
6.3.3 在需要mock的模块目录临近建立目录__mocks__
6.3.4 样例
// utils.jsexportdefault{add(a, b){
console.log('---------------util.js add----------');return a + b;}};// mock.jsimport utils from'./utils';exportdefault{test(){
console.log('---------------mock.js test----------');return utils.add(1,2);}};// mock.test.jsimport m from'./mock';import utils from'./utils';
jest.mock('./utils.js');it('mock 整个 fetch.js模块',()=>{
m.test();expect(utils.add).toBeCalledTimes(1);});
6.4 jest.spyOn()
jest.spyOn()方法同样创建一个mock函数,但是该mock函数不仅能够捕获函数的调用情况,还可以正常的执行被spy的函数。实际上,jest.spyOn()是jest.fn()的语法糖,它创建了一个和被spy的函数具有相同内部代码的mock函数。
import m from'./mock';import utils from'./utils';it('mock 整个 fetch.js模块',()=>{const y = jest.spyOn(utils,'add');
m.test();expect(y).toBeCalledTimes(1);});
- 使用
jest.mock()
时add方法实际没有执行
,使用jest.spyOn()
时add会被执行
七、wrapper.emitted()
每个挂载的包裹器都会通过其背后的 Vue 实例自动记录所有被触发的事件。你可以用 wrapper.emitted() 方法取回这些事件记录。
wrapper.vm.$emit('foo')
wrapper.vm.$emit('foo',123)/*
`wrapper.emitted()` 返回以下对象:
{
foo: [[], [123]]
}
*/
// 断言事件已经被触发expect(wrapper.emitted().foo).toBeTruthy()// 断言事件的数量expect(wrapper.emitted().foo.length).toBe(2)// 断言事件的有效数据expect(wrapper.emitted().foo[1]).toEqual([123])
你也可以调用 wrapper.emittedByOrder() 获取一个按触发先后排序的事件数组。
参考
- Vue测试指南(vue.js 2)
- vue中如何使用jest单元测试
- jest beforeEach 和beforeAll区别
- Jest 配置与 React Hook 单元测试教程
- jest手册
- Jest 使用指南 - - Mock 篇
- 【测试学习】UI测试工具vue-test-utils入门教程
版权归原作者 一天一丢丢 所有, 如有侵权,请联系我们删除。