Skip to content

Jest 简介 #103

@coconilu

Description

@coconilu

概述

Jest 被 Facebook 用来测试包括 React 应用在内的所有 JavaScript 代码。

特性:

  1. 高速和沙盒
  2. 内置代码覆盖率报告
  3. 无需配置
  4. 功能强大的模拟库

目录:

  1. 安装
  2. 运行
    • 配置
  3. 用法
    • 同步
    • 异步
    • 预备和收尾工作
    • Mock函数
  4. API
    • Globals
    • Expect
    • Mock Functions
    • The Jest Object
    • Configuring Jest
    • Jest CLI Options

安装

npm install --save-dev jest

运行

在 __tests__文件夹下放置你的测试用例,或者使用 .spec.js 或 .test.js 后缀给它们命名。
在项目的根目录运行jest,jest将会找到这些测试文件,并执行。

还可以通过命令行添加--config=config.json指定一个配置文件。

配置

可以配置在package.json,也可以在根目录创建配置文件jest.config.js

用法

同步

数值:toBe()
浮点:toBeCloseTo()
字符串的正则表达式:toMatch()
对象 / 数组:toEqual()
数组是否包含特定子项:toContain()
只匹配 null:toBeNull()
只匹配 undefined:toBeUndefined()
与 toBeUndefined 相反:toBeDefined()
匹配任何 if 语句为真:toBeTruthy()
匹配任何 if 语句为假:toBeFalsy()
抛出异常:toThrow()

异步

回调

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

test('the data is peanut butter', done => {
  function callback(data) {
    expect(data).toBe('peanut butter');
    done();
  }

  fetchData(callback);
});

Promises

需要从测试返回一个 Promise, Jest 会等待这一 Promise 来解决。

一定要返回 Promise - 如果你省略 return 语句,您的测试将在 fetchData 完成之前完成。

如果你想要 Promise 被拒绝,使用 .catch 方法。 请确保添加 expect.assertions 来验证一定数量的断言被调用。 否则一个fulfilled态的 Promise 不会让测试失败:

test('the fetch fails with an error', () => {
  expect.assertions(1);
  return fetchData().catch(e => expect(e).toMatch('error'));
});

.resolves / .rejects

test('the data is peanut butter', () => {
  expect.assertions(1);
  return expect(fetchData()).resolves.toBe('peanut butter');
});

test('the fetch fails with an error', () => {
  expect.assertions(1);
  return expect(fetchData()).rejects.toMatch('error');
});

Async/Await

若要编写 async 测试,只要在函数前面使用 async 关键字传递到 test。就可以跟同步写法一样了。

预备和收尾工作

如果有一些要为多次测试重复设置的工作,可以使用 beforeEach 和 afterEach。

在某些情况下,你只需要在文件的开头做一次设置。Jest 提供 beforeAll 和 afterAll 处理这种情况。

作用域

可以通过 describe 块来将测试分组。 当 before 和 after 的块在 describe 块内部时,则其只适用于该 describe 块内的测试。

仅运行一个测试

为了找出测试不通过的原因,可以使用test.only()让Jest仅运行某个测试代码。

test.only()
替代
test()

Mock函数

Mock函数的原因应该是使用了修饰器设计模式去代理一个函数,并观察函数相关参数。

使用 mock

// 
function forEach(items, callback) {
  for (let index = 0; index < items.length; index++) {
    callback(items[index]);
  }
}

const mockCallback = jest.fn(x => 42 + x);
forEach([0, 1], mockCallback);

// The mock function is called twice
expect(mockCallback.mock.calls.length).toBe(2);

// The first argument of the first call to the function was 0
expect(mockCallback.mock.calls[0][0]).toBe(0);

// The first argument of the second call to the function was 1
expect(mockCallback.mock.calls[1][0]).toBe(1);

// The return value of the first call to the function was 42
expect(mockCallback.mock.results[0].value).toBe(42);

.mock属性

Mock函数都有.mock属性,它是一个对象,包含了被执行的次数、返回值、实例化次数等等。

Mock 返回值

还可以手动设置mock函数的返回值,不需要写函数体。

Mocking 模块

模拟数据,便于测试功能。

比如模拟axios库:

import axios from 'axios';
jest.mock('axios');
axios.get.mockResolvedValue(resp);

API

Global

afterAll(fn, timeout)
afterEach(fn, timeout)
beforeAll(fn, timeout)
beforeEach(fn, timeout)
describe(name, fn)
describe.each(table)(name, fn, timeout)
describe.only(name, fn)
describe.only.each(table)(name, fn)
describe.skip(name, fn)
describe.skip.each(table)(name, fn)
test(name, fn, timeout)
test.each(table)(name, fn, timeout)
test.only(name, fn, timeout)
test.only.each(table)(name, fn)
test.skip(name, fn)
test.skip.each(table)(name, fn)

Expect

expect(value)
expect.extend(matchers)
expect.anything()
expect.any(constructor)
expect.arrayContaining(array)
expect.assertions(number)
expect.hasAssertions()
expect.not.arrayContaining(array)
expect.not.objectContaining(object)
expect.not.stringContaining(string)
expect.not.stringMatching(string | regexp)
expect.objectContaining(object)
expect.stringContaining(string)
expect.stringMatching(string | regexp)
expect.addSnapshotSerializer(serializer)
.not
.resolves
.rejects
.toBe(value)
.toHaveBeenCalled()
.toHaveBeenCalledTimes(number)
.toHaveBeenCalledWith(arg1, arg2, ...)
.toHaveBeenLastCalledWith(arg1, arg2, ...)
.toHaveBeenNthCalledWith(nthCall, arg1, arg2, ....)
.toHaveReturned()
.toHaveReturnedTimes(number)
.toHaveReturnedWith(value)
.toHaveLastReturnedWith(value)
.toHaveNthReturnedWith(nthCall, value)
.toBeCloseTo(number, numDigits)
.toBeDefined()
.toBeFalsy()
.toBeGreaterThan(number)
.toBeGreaterThanOrEqual(number)
.toBeLessThan(number)
.toBeLessThanOrEqual(number)
.toBeInstanceOf(Class)
.toBeNull()
.toBeTruthy()
.toBeUndefined()
.toContain(item)
.toContainEqual(item)
.toEqual(value)
.toHaveLength(number)
.toMatch(regexpOrString)
.toMatchObject(object)
.toHaveProperty(keyPath, value)
.toMatchSnapshot(propertyMatchers, snapshotName)
.toMatchInlineSnapshot(propertyMatchers, inlineSnapshot)
.toStrictEqual(value)
.toThrow(error)
.toThrowErrorMatchingSnapshot()
.toThrowErrorMatchingInlineSnapshot()

Mock Functions

mockFn.getMockName()
mockFn.mock.calls,包含被调用的所有次数和传入的参数
mockFn.mock.results,包含被调用返回的结果
mockFn.mock.instances
mockFn.mockClear()
mockFn.mockReset()
mockFn.mockRestore()
mockFn.mockImplementation(fn)
mockFn.mockImplementationOnce(fn)
mockFn.mockName(value)
mockFn.mockReturnThis()
mockFn.mockReturnValue(value)
mockFn.mockReturnValueOnce(value)
mockFn.mockResolvedValue(value)
mockFn.mockResolvedValueOnce(value)
mockFn.mockRejectedValue(value)
mockFn.mockRejectedValueOnce(value)

The Jest Object

jest.clearAllTimers()
jest.disableAutomock()
jest.enableAutomock()
jest.fn(implementation)
jest.isMockFunction(fn)
jest.genMockFromModule(moduleName)
jest.mock(moduleName, factory, options)
jest.unmock(moduleName)
jest.doMock(moduleName, factory, options)
jest.dontMock(moduleName)
jest.clearAllMocks()
jest.resetAllMocks()
jest.restoreAllMocks()
jest.resetModules()
jest.retryTimes()
jest.runAllTicks()
jest.runAllTimers()
jest.runAllImmediates()
jest.advanceTimersByTime(msToRun)
jest.runOnlyPendingTimers()
jest.requireActual(moduleName)
jest.requireMock(moduleName)
jest.setMock(moduleName, moduleExports)
jest.setTimeout(timeout)
jest.useFakeTimers()
jest.useRealTimers()
jest.spyOn(object, methodName)
jest.spyOn(object, methodName, accessType?)

Configuring Jest

automock [boolean]
bail [boolean]
browser [boolean]
cacheDirectory [string]
clearMocks [boolean]
collectCoverage [boolean]
collectCoverageFrom [array]
coverageDirectory [string]
coveragePathIgnorePatterns [array]
coverageReporters [array]
coverageThreshold [object]
errorOnDeprecated [boolean]
forceCoverageMatch [array]
globals [object]
globalSetup [string]
globalTeardown [string]
moduleDirectories [array]
moduleFileExtensions [array]
moduleNameMapper [object]
modulePathIgnorePatterns [array]
modulePaths [array]
notify [boolean]
notifyMode [string]
preset [string]
prettierPath [string]
projects [array]
reporters [array]
resetMocks [boolean]
resetModules [boolean]
resolver [string]
restoreMocks [boolean]
rootDir [string]
roots [array]
runner [string]
setupFiles [array]
setupTestFrameworkScriptFile [string]
snapshotSerializers [array]
testEnvironment [string]
testEnvironmentOptions [Object]
testMatch [array]
testPathIgnorePatterns [array]
testRegex [string]
testResultsProcessor [string]
testRunner [string]
testURL [string]
timers [string]
transform [object]
transformIgnorePatterns [array]
unmockedModulePathPatterns [array]
verbose [boolean]
watchPathIgnorePatterns [array]

Jest CLI Options

jest
--bail
--cache
--changedFilesWithAncestor
--changedSince
--ci
--clearCache
--collectCoverageFrom=
--colors
--config=
--coverage
--debug
--detectOpenHandles
--env=
--errorOnDeprecated
--expand
--findRelatedTests
--forceExit
--help
--init
--json
--outputFile=
--lastCommit
--listTests
--logHeapUsage
--maxWorkers=
--noStackTrace
--notify
--onlyChanged
--passWithNoTests
--projects ...
--reporters
--runInBand
--runTestsByPath
--setupTestFrameworkScriptFile=
--showConfig
--silent
--testNamePattern=
--testLocationInResults
--testPathPattern=
--testRunner=
--updateSnapshot
--useStderr
--verbose
--version
--watch
--watchAll
--watchman

参考

官方文档

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions