- 비동기 코드를 테스트 할 때는 언제 다음 테스트 코드로 넘어가야 되는지를 알려줘야 됨.
- Jest에서는 이런 경우를 다루는 여러가지 방법이 있음
Callbacks
callback을 사용하는 코드
const fetchDataCallback = (cb) => {
setTimeout(() => {
console.log("wait 3.5 sec.");
cb('peanut butter');
}, 3500);
};
잘못 된 테스트 방법
- callback 함수가 호출되지 않고 test 종료
- 잘못 된 결과가 나와도 테스트가 통과 됨
test('the data is peanut butter', () => {
function callback(data) {
expect(data).toBe('peanut butter');
}
fetchDataCallback(callback);
});
올바른 테스트 방법
- test 함수의 인자로 done을 받아서 사용
- done이 호출되어야 테스트 종료
- 테스트가 실패하는 경우를 대비해서 try, catch로 예외 처리
test('the data is peanut butter', done => {
function callback(data) {
try {
expect(data).toBe('peanut butter');
done();
} catch (error) {
done(error);
}
}
fetchDataCallback(callback);
});
Promises
promise를 return하는 코드
const fetchDataPromise = () => {
return new Promise(resolve => {
return setTimeout(() => {
console.log("wait 3.5 sec.");
resolve('peanut butter');
}, 3500);
});
}
const fetchDataThrowError = () => {
return new Promise((resolve, reject) => {
return setTimeout(() => {
console.log("wait 3.5 sec.");
reject('error reason');
}, 3500);
});
}
테스트 방법
- test 코드에서 promise를 return
return 안하면 callback을 이용한 방법에서 done을 빠뜨린 것과 같음
- promise의 resolve가 호출 될 때 까지 기다림
- promise의 reject가 호출 될 경우 테스트 실패
- promise 코드 안의 assertion 코드가 실제로 호출 됐는지는 expect.assertions 함수로 확인 가능
then/catch
를 이용하는 방법과 resolves/rejects
를 이용하는 방법이 존재
describe('Promises then/catch', () => {
test('the data is peanut butter', () => {
return fetchDataPromise().then(data => {
expect(data).toBe('peanut butter');
});
});
test('the test is rejected', () => {
return fetchDataThrowError().catch(error => {
expect.assertions(1);
expect(error).toMatch('error reason');
});
})
});
describe('Promises resolves/rejects', () => {
test('the data is peanut butter', () => {
return expect(fetchDataPromise()).resolves.toBe('peanut butter');
});
test('the test is rejected', () => {
expect.assertions(1);
return expect(fetchDataThrowError()).rejects.toMatch('error reason');
})
});
Async/Await
테스트 방법
- test에 넘기는 함수 앞에
async
키워드 추가
- promise를 반환하는 함수 호출 앞에
await
키워드 추가
resolves/rejects
와 혼합해서 사용 가능
describe('Async/Await', () => {
test('the data is peanut butter', async () => {
const data = await fetchDataPromise();
expect(data).toBe('peanut butter');
});
test('the fetch fails with an error', async () => {
expect.assertions(1);
try {
await fetchDataThrowError();
} catch(error) {
expect(error).toMatch('error reason');
}
});
});
describe('Async/Await with resolves/rejects', () => {
test('the data is peanut butter', async () => {
await expect(fetchDataPromise()).resolves.toBe('peanut butter');
});
test('the fetch fails with an error', async () => {
expect.assertions(1);
await expect(fetchDataThrowError()).rejects.toMatch('error reason');
});
});