【jest使用】

Quick Start

安装:
npm install --save-dev jest

让我们开始为一个假设函数编写测试,该函数将两个数字相加。 首先,创建一个 sum.js 文件:

function sum(a, b) {
  return a + b;
}
module.exports = sum;

然后,创建一个名为 sum.test.js 的文件。jest会自动找对应的test作为测试文件,所以我们这里也使用了.test文件名。 这将包含我们的实际测试:

const sum = require('./sum');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});
  • test方法:需要测试的代码
  • expect方法 :预期方法,就是你调用了什么方法,传递了什么参数,得到的预期是什么

将下面的配置部分添加到你的 package.json 里面:

{
  "scripts": {
    "test": "jest"
  }
}

最后,运行 yarn testnpm run test ,Jest将打印下面这个消息:

PASS  ./sum.test.js
✓ adds 1 + 2 to equal 3 (5ms)

若需要每次修改控制台就会自动跑测试代码,可配置:

{
  "scripts": {
    "test": "jest --watchAll"
  }
}
测试覆盖率生成

在jest.config.js里面配置coverageDirectory : "coverage" ,coverageDirectory为输出覆盖信息文件的目录

const {defaults} = require('jest-config');
module.exports = {
  moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts', 'tsx'],
  coverageDirectory : "coverage" 
};

使用npx jest --coverage即可生成一个代码测试覆盖率的说明

让jest支持ES6

由于jest不支持ES6,需要配置babel进行ES6的转换

安装依赖:

npm install --save-dev babel-jest @babel/core @babel/preset-env

可以在工程的根目录下创建一个babel.config.js文件用于配置与你当前Node版本兼容的Babel:

// babel.config.js
module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        targets: {
          node: 'current',
        },
      },
    ],
  ],
};

创建jest.config.js

// jest.config.js
const {defaults} = require('jest-config');
module.exports = {
  moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts', 'tsx']
};
jest中的匹配器(详细可查看官网

toBe 使用 Object.is 判断是否严格相等。

toEqual 递归检查对象或数组的每个字段。

toBeNull 只匹配 null

toBeUndefined 只匹配 undefined

toBeDefined 只匹配非 undefined

toBeTruthy 只匹配真。

toBeFalsy 只匹配假。

toBeGreaterThan 实际值大于期望。

toBeGreaterThanOrEqual 实际值大于或等于期望值

toBeLessThan 实际值小于期望值。

toBeLessThanOrEqual 实际值小于或等于期望值。

toBeCloseTo 比较浮点数的值,避免误差。

toMatch 正则匹配。

toContain 判断数组中是否包含指定项。

toHaveProperty(keyPath, value) 判断对象中是否包含指定属性。

toThrow 判断是否抛出指定的异常。

toBeInstanceOf 判断对象是否是某个类的实例,底层使用 instanceof

jest进行异步测试(详细可查看官网

有一个异步请求接口fetchData,对其进行单元测试,代码如下:

//fetchData.js
import axios from 'axios';

export const fetchData = (fn)=>{
    axios.post('接口').then((response)=>{
      fn(response.data.responseCode);
  })
}
//fetchData.test.js
import { fetchData } from '../fetchData.js'

test('fetchData 测试',()=>{
    fetchData((res)=>{
    	expect(res).toEqual('接口返回的值');
    })
})

注意这样写是有问题的,因为方法还没有等到回调,我们的结果已经完成了,所以这时候你对于没测试完,只是方法可用,就返回了测试结果,这种结果是不保证正确的。

方法一:使用单个参数调用 done,而不是将测试放在一个空参数的函数。 Jest会等done回调函数执行结束后,结束测试。

//fetchData.test.js
import { fetchData } from '../fetchData.js'

test('fetchData 测试',(done)=>{
    fetchData((res)=>{
    	expect(res).toEqual(str);
        done();
    })
})

方法二:使用Promise的方式,fetchData 不使用回调函数,而是返回一个 Promise

//fetchData.js
export const fetchData = () => {
  return axios.post('接口');
}

返回一个promise

//fetchData.test.js
test('fetchData 测试', () => {
  return fetchData().then(res => {
    expect(res.data.responseCode).toEqual('接口返回的值'); //res.data.responseCode 接口自定义的数据结构
})

不要忘记把 promise 作为返回值⸺如果你忘了 return 语句的话,在 fetchData 返回的这个 promise 被 resolve、then() 有机会执行之前,测试就已经被视为已经完成了。

同样的,可以通过.catch来测试异常情况

//fetchData.test.js
test('fetchData 测试', () => {
  return fetchData().catch(err => {
    expect(err).toEqual('error'); 
})

这里需要说明一下,只有出现异常的时候才会走这个方法,若没有出现异常,就不会走这个测试方法,而Jest会默认这个用例通过了测试。因此需要使用expect.assertions(1),这个代码的意思是“断言,必须需要执行一次expect方法才可以通过测试”。

//fetchData.test.js
test('fetchData 测试', () => {
  expect.assertion(1);
  return fetchData().catch(err => {
    expect(err).toEqual('error'); 
})

方法三:使用async/await方式

//fetchData.js
export const fetchData = () => {
  return axios.post('接口');
}

返回一个promise

//fetchData.test.js
test('fetchData 测试', async () => {
  let res = await fetchData();
  expect(res.data.responseCode).toEqual('接口返回的值');
})
jest使用Mock进行测试(详细可查看官网

jest提供了Mock方法,可以通过jest.fn()编写mock方法

const myMock = jest.fn(res => {console.log('mock....')});

myMock();  // mock....

通过jest.mock()对已有的方法或模块进行mock

// foo.js
export const foo = () => {
  //do something...
}

// test.js
import { foo } from './foo'
jest.mock('./foo'); //mock foo 

foo.mockImplementation(() => 42);
foo();  // 42

或者可以这样

// foo.js
export const foo = () => {
  //do something...
}

// test.js
import { foo } from './foo'
jest.mock('./foo', () => { //mock foo 
    return {
        foo: jest.fn(() => 42);
    }
});

foo();  // 42

注: jest不支持ES6,若要使用import、export等需要进行babel转换

Q&A

1.jest.mock()模块工厂不允许引用任何范围外的变量

例如:

import { demo } from './demo';
import { foo } from './foo';
jest.mock('./foo', () => {
	demo();
});

此时会报错

The module factory of `jest.mock()` is not allowed to reference any out-of-scope variables.
    Invalid variable access: str
    Allowed objects: Array, ArrayBuffer, Atomics, BigInt, BigInt64Array, BigUint64Array, Boolean, Buffer, COUNTER_HTTP_CLIENT_REQUEST, COUNTER_HTTP_CLIENT_RESPONSE, COUNTER_HTTP_SERVER_REQUEST, COUNTER_HTTP_SERVER_RESPONSE, COUNTER_NET_SERVER_CONNECTION, COUNTER_NET_SERVER_CONNECTION_CLOSE, DTRACE_HTTP_CLIENT_REQUEST, DTRACE_HTTP_CLIENT_RESPONSE, DTRACE_HTTP_SERVER_REQUEST, DTRACE_HTTP_SERVER_RESPONSE, DTRACE_NET_SERVER_CONNECTION, DTRACE_NET_STREAM_END, DataView, Date, Error, EvalError, Float32Array, Float64Array, Function, GLOBAL, Generator, GeneratorFunction, Infinity, Int16Array, Int32Array, Int8Array, InternalError, Intl, JSON, Map, Math, NaN, Number, Object, Promise, Proxy, RangeError, ReferenceError, Reflect, RegExp, Set, SharedArrayBuffer, String, Symbol, SyntaxError, TypeError, URIError, URL, URLSearchParams, Uint16Array, Uint32Array, Uint8Array, Uint8ClampedArray, WeakMap, WeakSet, WebAssembly, arguments, clearImmediate, clearInterval, clearTimeout, console, decodeURI, decodeURIComponent, encodeURI, encodeURIComponent, escape, eval, expect, global, isFinite, 
isNaN, jest, parseFloat, parseInt, process, require, root, setImmediate, setInterval, setTimeout, undefined, unescape.
    Note: This is a precaution to guard against uninitialized mock variables. If it is ensured that the mock is required lazily, variable names prefixed with `mock` (case insensitive) are permitted.

解决方案:

可使用jest.requireActual()

import { demo } from './demo';
import { foo } from './foo';
jest.mock('./foo', () => {
	const res = jest.requireActual('./demo')
    res.demo();
});

参考

https://jestjs.io/docs/zh-Hans/getting-started

  • 21
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值