jest函数单元测试

一、总体概念

jest单元测试的写法为三步,引入测试内容,运行测试内容,最后进行比较,是否达到预期。

Jest中的断言使用expect, 它接受一个参数,就是运行测试内容的结果,返回一个对象,这个对象来调用匹配器(toBe/。。。。) ,

匹配器的参数就是我们的预期结果,这样就可以对结果和预期进行对比了,也就可以判断对不对了

1、两个必会的方法

  • test方法:Jest封装的测试方法,一般填写两个参数,描述和测试方法

  • expect方法 :预期方法,就是你调用了什么方法,传递了什么参数,得到的预期是什么

2、匹配器:

  1. toBe():绝对相等(===)
  2. toEqual():简单类型绝对匹配;复杂类型内容结果的匹配
  3. toBeNull():匹配null
  4. toBeUndefined():匹配undefined
  5. toBeDefined():匹配非undefined
  6. toBeTruthy():匹配转化后为true
  7. toBeFalsy():匹配转化后为false
  8. toBeGreaterThan():相当于大于号
  9. toBeLessThan():相当于小于号
  10. toBeGreaterThanOrEqual():相当于大于等于号
  11. toBeLessThanOrEqual():相当于大于等于号
  12. toBeCloseTo():解决js浮点错误
  13. toMatch(regExp/string):用正则表达式或者字符串匹配字符串片段
  14. toContain():匹配数组或者Set中的某一项
  15. toThrow():匹配异常处理,如果抛出了异常就过测试用例
expect({a:1}).toBe({a:1})//判断两个对象是否相等
expect(1).not.toBe(2)//判断不等
expect(n).toBeNull(); //判断是否为null
expect(n).toBeUndefined(); //判断是否为undefined
expect(n).toBeDefined(); //判断结果与toBeUndefined相反
expect(n).toBeTruthy(); //判断结果为true
expect(n).toBeFalsy(); //判断结果为false
expect(value).toBeGreaterThan(3); //大于3
expect(value).toBeGreaterThanOrEqual(3.5); //大于等于3.5
expect(value).toBeLessThan(5); //小于5
expect(value).toBeLessThanOrEqual(4.5); //小于等于4.5
expect(value).toBeCloseTo(0.3); // 浮点数判断相等
expect('Christoph').toMatch(/stop/); //正则表达式判断
expect(['one','two']).toContain('one'); //匹配数组

function compileAndroidCode() {
  throw new ConfigError('you are using the wrong JDK');
}

test('compiling android goes as expected', () => {
  expect(compileAndroidCode).toThrow();
  expect(compileAndroidCode).toThrow(ConfigError); //判断抛出异常
})

 3、describe()测试分组

Jest为我们提供了一个分组的语法describe(),创建一个测试集。

这个方法接受两个参数,它的语法和test 的一致,第一个参数也是字符串,对这一组测试进行描述, 第二个参数是一个函数,函数体就是一个个的test 测试。

在jest中,test和it一样,接受两个参数,第一个是字符串,对这个测试进行描述,需要什么条件,达到什么效果。第二个是函数,函数体就是真正的测试代码,jest 要执行的代码

 对一个功能进行测试,但它分为多种情况,需要多个test或it, 最好使用descibe() 把多个test 包起来,形成一组测试。只有这一组都测试完成之后,才能说明这个功能是好的。

import {isTrueOrFasle} form './tools' ;

describe('true or false', () => {
    
    it('should return true when input true', () => {
        let result = isTrueOrFasle(true);
        expect(result).toBeTruthy();  // toBeTruthy 匹配器
    })

    test('should return false when input fasle', () => {
        let result = isTrueOrFasle(false);
        expect(result).toBeFalsy();  // toBeFalsy 匹配器
    })
})

4、异步代码测试

回调函数/promise/asyn await
参考:https://www.cnblogs.com/SamWeb/p/11454923.html

expect.assertions(1); //断言,表示必须执行一次expect 代码才算执行完

test('test axios async await', async() => {
    const res = await fetchThreeData();
    expect(res.data).toEqual({
        success: true
    })
})

5、Mock函数

 有时进行单元测试时,要测试的内容依赖其他内容,比如异步请求,会依赖网络,很可能造成测试达不到效果。 能不能把依赖变成可控的内容?这就用到Mock。Mock就是把依赖替换成我们可控的内容,实现测试的内容和它的依赖项隔离。那怎么才能实现mock呢?使用Mock 函数。在jest中,当我们谈论Mock的时候,其实谈论的就是使用Mock 函数代替依赖。Mock函数就是一个虚拟的或假的函数,所以对它来说,最重要的就是实现依赖的全部功能,从而起到替换的作用。通常,mock函数会提供以下三个功能,来实现替换:函数的调用捕获,设置函数返回值,改变原函数的实现。

在jest 创建一个Mock 函数最简单的方法就是调用jest.fn() 方法。

1.函数的调用捕获。捕获调用指的是这个函数有没有被调用,调用的参数是什么,返回值是什么,通常用于测试回调函数,模拟真实的回调函数。就像下边的forEachFun函数,它接受一个回调函数,每个调用者都会传递不同的回调函数过来,我们事先并不知道回调函数,再者我们测试forEach 的重点是,该函数是不是把数组中的每一项都传递给回调函数了,所以回调函数只要是一个函数就可以了,但该函数必须把调用的信息都保存下来,这就是Mock 函数的调用捕获,为此mock 函数还有一个mock 属性。

测试中就使用jest.fn() 生成的mock 函数来模拟真实的回调函数。

// mock的第一个用处:调用函数的捕获
export const forEachFun = (array: any[], callback: Function) => {
  array.forEach((i) => callback(i));
};

test('should call callback everyone', () => {
  const mockFun = jest.fn(); // 模拟函数
  const testArr = [1, 2];
  forEachFun(testArr, mockFun);
  console.log(30, mockFun.mock);
  expect(mockFun.mock.calls.length).toBe(2);
});

mock函数mockFun的mock 属性是一个对象,打印结果:

{
  calls: [ [ 1 ], [ 2 ] ],   instances: [ undefined, undefined ],   invocationCallOrder: [ 1, 2 ],   results:[
        { type:
'return', value: undefined },         { type: 'return', value: undefined }
  ]
}
  •  calls 保存的就是调用状态。calls 是一个数组,每一次的调用都组成数组的一个元素,在这里调用了两次,就有两个元素。每一个元素又是一个数组,它则表示的是函数调用时的参数,因为每次的调用都传递了一个参数给函数,所以数组只有一项。如果有多个参数,数组就有多项,按照函数中的参数列表依次排列。这时候,就可以做断言,函数调用了几次,就判断calls.length. expect(mockFun.mock.calls.length).toBe(2) 就是断言函数是不是调用了两次。expcet(mockFun.mock.calls[0][0]) .toBe(1)就是断言第一次调用的时候传递的参数是不是1. 可能觉得麻烦了, 的确有点麻烦了,幸好,jest 对函数的mock参数进行了简单的封装,提供了简单的匹配器

   toHaveBeenCalled()/toBeCalled():用来判断mock函数是否被掉用过;

   toHaveBeenCalledTimes(number)/toBeCalledTimes(number):用来判断mock函数调用过几次;

   toHaveBeenCalledWith(arg1,arg2,...)/toBeCalledWith(arg1,arg2,...):用来判断是否使用了特定参数调mock函数

   ..... 参考官网

test('should call callback everyone', () => {
  const mockFun = jest.fn();
  const testArr = [1, 2];
  forEachFun(testArr, mockFun);
  expect(mockFun).toHaveBeenCalled();
});
  • results保存的就是返回值。

2.设置函数返回值。有的时候,不想调用函数,直接获取到函数的返回值就可以了,比如异步函数, 以fetchData 为例,它直接返回一个promise 就好了,根本没有必要请求服务器。

mock函数有mockReturnValue(),  它的参数就是返回值。不过它不能返回promise.。

可以使用mockResolvedValue直接返回promise的值. 对fetchData 进行mock, 然后设置它的mockResolvedValue()


test('should return data when fetchData request success', () => {
   const fetchData = jest.fn();
    fetchData.mockResolvedValue({name: 'sam'})
   return fetchData().then(res => {
       expect(res).toEqual({name: 'sam'})
   })
})

3.改变函数实现。 有时不想使用默认的mock函数jest.fn(),尤其是测试回调函数的时候,你想提供回调函数实现,比如上面的forEach, 确实写一个真实的回调函数进行测试,心里更有底一点。mock 函数实现也有两种方法,jest.fn() 可以接受一个参数,这个参数就可以是一个函数实现。forEach 中的mock 函数就可以成mock 函数提供了一个方法mockImplementation(), 它的参数也是一个函数实现,使用mockImplementation() 来mock fetchData,让它返回{name: 'sam'}

 

 注:VSCode的终端窗口中输入yarn test 就可以进行测试了

  • 配置jest :npx jest --init
  • 生成代码覆盖率:npx jest --coverage
  • Jest识别三种测试文件:
    • 测试文件后缀为js,jsx,ts,tsx
    • 测试文件需要放在tests/unit/目录下或者是/__tests__/目录下
    • 以xx.test.js/...结尾的文件,以xx.spec.js/...结尾的文件,
      只要满足这三个要求的测试文件,使用运行jest时就会自动执行

posted @ 2020-06-01 17:22  心晴安夏  阅读(5524)  评论(2编辑  收藏  举报