Jest Expect API
Jest Expect API (매처)
테스트를 작성하다 보면 값이 특정 조건을 만족하는지 확인해야 할 때가 많아요. expect는 그 '확인'을 위한 매처(matcher) 함수들을 제공하는 진입점이에요. 어떤 값이 기대와 같은지, 또는 기대와 다른지를 한 줄로 검증할 수 있게 해 줘요.
expect(value)
expect는 값을 테스트할 때마다 쓰여요. 단독으로 호출하기보다는 매처(matcher) 함수와 함께 사용해요.
예를 들어 bestLaCroixFlavor()가 'grapefruit'를 반환해야 한다면 이렇게 테스트해요.
test('the best flavor is grapefruit', () => {
expect(bestLaCroixFlavor()).toBe('grapefruit');
});
여기서 toBe가 매처에요. expect의 인자는 코드가 만들어낸 값, 매처의 인자는 '올바른 값'이에요. 둘을 뒤바꿔도 테스트는 돌지만 실패 메시지가 이상해지니 순서를 지켜요.
Modifiers (수식자)
expect와 매처 사이에는 동작을 바꾸는 수식자들이 들어갈 수 있어요.
.not — 반대를 테스트해요.
test('the best flavor is not coconut', () => {
expect(bestLaCroixFlavor()).not.toBe('coconut');
});
.resolves — fulfilled 프로미스의 값을 풀어서 다른 매처를 이어서 쓸 수 있게 해요. 프로미스가 reject되면 단언이 실패해요.
test('resolves to lemon', async () => {
await expect(Promise.resolve('lemon')).resolves.toBe('lemon');
});
.rejects — rejected 프로미스의 이유(reason)를 풀어서 다른 매처를 이어서 써요.
test('rejects to octopus', async () => {
await expect(Promise.reject(new Error('octopus'))).rejects.toThrow('octopus');
});
Matchers (주요 매처)
테스트에서 자주 쓰이는 매처 몇 개를 살펴볼게요.
.toBe(value) — 원시 값 비교 또는 객체 인스턴스의 참조 동일성 검사. ===보다 낫다고 여겨지는 Object.is를 사용해 비교해요. 부동소수점은 쓰지 마세요 — 0.2 + 0.1은 0.3과 엄밀히 같지 않아요. 부동소수점은 .toBeCloseTo를 쓰는 게 좋아요.
const can = {
name: 'pamplemousse',
ounces: 12,
};
describe('the can', () => {
test('has 12 ounces', () => {
expect(can.ounces).toBe(12);
});
test('has a sophisticated name', () => {
expect(can.name).toBe('pamplemousse');
});
});
.toHaveBeenCalled() — mock 함수가 호출됐는지 확인해요.
function drinkAll(callback, flavour) {
if (flavour !== 'octopus') {
callback(flavour);
}
}
describe('drinkAll', () => {
test('drinks something lemon-flavoured', () => {
const drink = jest.fn();
drinkAll(drink, 'lemon');
expect(drink).toHaveBeenCalled();
});
});
.toHaveBeenCalledTimes(number) — mock 함수가 정확히 N번 호출됐는지 확인해요.
const drink = jest.fn();
drinkEach(drink, ['lemon', 'octopus']);
expect(drink).toHaveBeenCalledTimes(2);
.toHaveBeenCalledWith(arg1, arg2, ...) — mock 함수가 특정 인자로 호출됐는지 확인해요. 인자 비교는 .toEqual과 같은 알고리즘을 사용해요.
.toHaveBeenLastCalledWith(...) — 마지막 호출의 인자를 확인해요. .toHaveBeenNthCalledWith(nthCall, ...) — n번째 호출의 인자를 확인해요 (n은 1부터 시작하는 양의 정수).
.toHaveLength(number) — 배열/문자열 길이 확인. .toHaveProperty(keyPath, value?) — 객체가 특정 속성을 갖는지 확인해요.
.toBeCloseTo(number, numDigits?) — 부동소수점 근사 비교. .toBeDefined(), .toBeUndefined(), .toBeNull(), .toBeNaN() — 값의 존재/종류 확인.
.toBeGreaterThan(number | bigint), .toBeGreaterThanOrEqual, .toBeLessThan, .toBeLessThanOrEqual — 크기 비교.
.toBeInstanceOf(Class) — 인스턴스 타입 확인. .toBeFalsy(), .toBeTruthy() — 불리언 진리성.
.toContain(item) — 배열/문자열이 항목 포함. .toEqual(value) — 객체 값의 깊은 동등 비교. .toMatch(regexp | string) — 정규식/문자열 매칭. .toMatchObject(object) — 부분 객체 매칭.
.toStrictEqual(value) — undefined 속성, 배열 희소성 등까지 엄밀하게 비교하는 깊은 동등.
.toThrow(error?) — 함수가 예외를 던지는지 확인.
Asymmetric Matchers (비대칭 매처)
부분 일치를 위해 쓸 수 있는 매처들이에요.
expect.anything(); // null/undefined가 아닌 것
expect.any(constructor); // 주어진 생성자의 인스턴스
expect.arrayContaining(array);
expect.objectContaining(object);
expect.stringContaining(string);
expect.stringMatching(regexp);
expect.closeTo(number, numDigits?);
test('contains lemon and octopus', () => {
expect(['lemon', 'octopus']).toEqual(expect.arrayContaining(['lemon']));
});
Assertion Count
expect.assertions(number) — 테스트가 최소 N번 단언한다고 선언. expect.hasAssertions() — 최소 1번의 단언이 실행됨을 보장.
Extend Utilities (매처 확장)
expect.extend(matchers) — 커스텀 매처를 Jest에 추가해요.
import { expect } from '@jest/globals';
function toBeWithinRange(actual, floor, ceiling) {
if (typeof actual !== 'number' || typeof floor !== 'number' || typeof ceiling !== 'number') {
throw new TypeError('These must be of type number!');
}
const pass = actual >= floor && actual <= ceiling;
if (pass) {
return {
message: () =>
`expected ${this.utils.printReceived(actual)} not to be within range ${this.utils.printExpected(` ${floor} - ${ceiling} `)}`,
pass: true,
};
} else {
return {
message: () =>
`expected ${this.utils.printReceived(actual)} to be within range ${this.utils.printExpected(` ${floor} - ${ceiling} `)}`,
pass: false,
};
}
}
expect.extend({ toBeWithinRange });
커스텀 매처는 this.utils 같은 컨텍스트 헬퍼를 쓰기 위해 일반 함수로 정의해야 해요 (화살표 함수 안 됨). expect.addEqualityTesters(testers), expect.addSnapshotSerializer(serializer)도 있어요. Jest 커뮤니티가 만든 추가 매처는 jest-extended를 참고해요.
더 알아보기
- Using Matchers - 매처 사용 개요
- Mock Functions - mock 함수와 매처 결합
- Snapshot Testing - 스냅샷 매처