비동기 예제
먼저, Getting Started 가이드의 내용을 따라 Jest에 Babel 지원을 활성화하세요.
API에서 사용자 데이터를 가져오고 사용자 이름을 반환하는 모듈을 구현해 봅시다.
// user.js
import request from './request';
export function getUserName(userID) {
return request('/users/' + userID).then(user => user.name);
}
위 구현에서 request.js 모듈이 프로미스를 반환할 것으로 기대합니다. 사용자 이름을 받기 위해 then을 호출하도록 연결합니다.
이제 네트워크에 접근하여 사용자 데이터를 가져오는 request.js의 구현을 상상해보세요:
// request.js
const http = require('http');
export default function request(url) {
return new Promise(resolve => {
// 이것이 API로부터 사용자 데이터를 가져오는 예에 대한
// HTTP 요청의 예입니다.
// 이 모듈은 __mocks__/request.js에 모의 되고 있습니다
http.get({path: url}, response => {
let data = '';
response.on('data', _data => (data += _data));
response.on('end', () => resolve(data));
});
});
}
테스트를 위해서 네트워크에 접근하는 것은 원치 않기 때문에, __mocks__ 폴더에 request.js 모듈에 대한 수동 모의를 만들 것입니다 (폴더는 대소문자를 구분하며, __MOCKS__은 동작하지 않을 것입니다). 이것은 다음과 같이 보일 수 있습니다:
// __mocks__/request.js
const users = {
4: {name: 'Mark'},
5: {name: 'Paul'},
};
export default function request(url) {
return new Promise((resolve, reject) => {
const userID = parseInt(url.substr('/users/'.length), 10);
process.nextTick(() =>
users[userID]
? resolve(users[userID])
: reject({
error: 'User with ' + userID + ' not found.',
}),
);
});
}
이제 비동기 기능에 대한 테스트를 작성해봅시다.
// __tests__/user-test.js
jest.mock('../request');
import * as user from '../user';
// 프로미스에 대한 단언이 반환되어야 합니다.
it('works with promises', () => {
expect.assertions(1);
return user.getUserName(4).then(data => expect(data).toEqual('Mark'));
});
Jest에게 수동 모의를 사용하도록 요청하는 jest.mock('../request')을 호출합니다. it는 리졸브 될 프로미스가 되는 값을 반환한 것으로 기대합니다. 마지막에 프로미스를 반환하기만 하면 원하는 만큼 많은 프로미스를 연결하고 언제든지 expect를 호출 할 수 있습니다.
.resolves
다른 매처와 함께 수행된 프로미스의 값을 펼치기 위해 resolves를 사용하는 덜 장황한 방법이 있습니다. 프로미스가 거부된다면, 단언은 실패할 것입니다.
it('works with resolves', () => {
expect.assertions(1);
return expect(user.getUserName(5)).resolves.toEqual('Paul');
});
async/await
async/await를 사용하여 테스트를 작성하는 것도 가능합니다. 이전의 동일한 예제를 작성하는 방법은 다음과 같습니다:
// async/await가 사용될 수 있습니다.
it('works with async/await', async () => {
expect.assertions(1);
const data = await user.getUserName(4);
expect(data).toEqual('Mark');
});
// async/await는 또한 `.resolves`와 함께 사용될 수 있습니다.
it('works with async/await and resolves', async () => {
expect.assertions(1);
await expect(user.getUserName(5)).resolves.toEqual('Paul');
});
프로젝트에 async/await를 활성화 하기 위해, @babel/preset-env을 설치하고 babel.config.js 파일에 기능을 활성화 시키세요.
오류 처리
오류는 .catch 메서드를 사용하여 처리될 수 있습니다. 특정 번호의 단언이 호출되는지를 확인하도록 expect.assertions을 추가하세요. 그렇지 않으면 수행된 프로미스는 테스트를 실패하지 않을 것입니다:
// Promise.catch를 사용하여 비동기 오류 테스트하기.
it('tests error with promises', () => {
expect.assertions(1);
return user.getUserName(2).catch(e =>
expect(e).toEqual({
error: 'User with 2 not found.',
}),
);
});
// 또는 async/await 사용.
it('tests error with async/await', async () => {
expect.assertions(1);
try {
await user.getUserName(1);
} catch (e) {
expect(e).toEqual({
error: 'User with 1 not found.',
});
}
});
.rejects
.rejects 헬퍼는 .resolves 헬퍼 처럼 동작합니다. 프로미스가 수행되면, 테스트는 자동으로 실패할 것입니다. expect.assertions(number)가 필수는 아니지만, 테스트 동안 호출되는 특정 번호의 assertions을 확인 하기 위해 권장됩니다. 그렇지 않으면 .resolves 단언을 return/await 하는 것을 잊어버리기 쉽습니다.
// `.rejects`를 사용하여 비동기 오류 테스트 하기.
it('tests error with rejects', () => {
expect.assertions(1);
return expect(user.getUserName(3)).rejects.toEqual({
error: 'User with 3 not found.',
});
});
// 또는 `.rejects`와 함께 async/await 사용.
it('tests error with async/await and rejects', async () => {
expect.assertions(1);
await expect(user.getUserName(3)).rejects.toEqual({
error: 'User with 3 not found.',
});
});
이 예제의 코드는 examples/async에서 사용 가능 합니다.
setTimeout 같은 타이머를 테스트하고 싶다면, 타이머 모의 문서를 살펴보세요.