Dog foot print

[JEST] 비동기 코드 테스트 본문

TDD/JEST

[JEST] 비동기 코드 테스트

개 발자국 2021. 5. 16. 17:48

Note : 자바스크립트의 코드는 비동기적으로 작동합니다. 개발자가 코드를 비동기적으로 실행 할 때, 이를 위해 제스트에게 이 코드가 언제 완료 되는지 알려 주어야 합니다.

callback 을 이용하기

비동기 코드를 확인 하는 가장 일반적인 방법은 콜백을 이용하는 것 입니다.

예를 들어, fetchData(callBack) 의 함수를 사용하는 경우, 함수는 어떤 데이터를 패치하고 마무리 되면 callback(data) 를 호출하게 될 것입니다. 아래의 코드에서는 ‘peanut butter’ 라는 string이 전달되는데, 개발자는 이를 확인 하고 싶을 겁니다.

function fetchData(callBack){  
setTimeout(()=>{  
callBack("peanut butter");  
},1000)  
}

// Don't do this!  
test('the data is peanut butter', () => {  
function callback(data) {  
expect(data).toBe('peanut butter');  
}

fetchData(callback);  
});  

위의 코드는 제대로 작동하지 않습니다. JEST는 test 구문을 모두 해석하면, 테스트를 종료하기 때문입니다 . 정확히 말하면, JEST는 데이터가 fetch되기 전에 테스트를 종료합니다.

그러나, 위의 코드를 제대로 동작시킬 방법이 존재합니다. 바로 test함수의 두번 째 콜백의 첫번째 전달인자인 done 함수를 사용하는 것입니다. test내부에서 done을 호출하는 경우, 제스트는 done함수가 실행되기 전까지 테스트를 종료하지 않게 됩니다.

test(‘the data is peanut butter’, done => {  
function callback(data) {  
try {  
expect(data).toBe(‘peanut butter’);  
done(); //if expect() throw error this done is never reach  
} catch (error) {  
done(error);  
}  
}

fetchData(callback);  
});  

만약 done 함수가 영원히 호출 되지 않으면, 테스트는 이를 실패 처리 할 것 입니다.

만약 expect에러가 실패한다면, expect 함수는 에러를 발생 시키게 됩니다. 그렇다면 done() 에 도달하지 못하고 로그가 남지 않게 됩니다. 그렇기에 위 코드에서는 expect가 실패하는 경우를 로그에 남기기 위해 try catch 블락으로 감쌌습니다. 에러 상황 또한 expect 함수 호출을 통해 처리 가능합니다.

Promise 사용

만약 코드에서 promise를 이용한다면, 더욱 깔끔하게 비동기 코드를 테스트 할 수 있습니다. Test에서 promise객체를 리턴한다면, 제스트는 promise가 resolve 함수를 호출하기를 기다릴 겁니다. 이 경우 만약 promise가 reject를 호출하게 된다면, 함수는 자동으로 실패처리 될 것 입니다.

예를 들어, 위에서 정의한 fetchData함수가 콜백함수를 인자로 받지 않고, promise를 반환한다고 코드를 작성하겠습니다. 이 경우, resolve로 ‘peanut butter’를 전달 하게 끔 코드를 변경 하겠습니다.

function fetchData(){  
return new Promise((resolve,reject)=>{  
setTimeout(()=>{  
resolve("peanut butter");  
},1000)  
})  
}  
test(‘the data is peanut butter’, () => {  
return fetchData().then(data => {  
expect(data).toBe(‘peanut butter’);  
});  
});  

Note : Test 함수의 2번 째 콜백이 promise 객체를 반환해야 합니다. 테스트 콜백이 프라미스 객체를 리턴하기 전에, fetchData의 resolve가 실행된다면 테스트가 이미 완료 되어버리고, then()구문이 실행되게 됩니다.

만약 프라미스객체가 reject를 호출하길 기대한다면 .catch 메서드를 사용하세요. 이를 확실히 하기위해 expect.assertions(assertion : number)를 테스트 코드에서 함께 호출하면 비동기 코드가 몇번 실행 되었는지 확인 할 수 있습니다.

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

.resolves/.rejects

개발자는 expect구문의 .resolves구문을 사용하여 .then과 .catch구문에 존재하는 콜백을 함축 시킬 수 있습니다.

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

Note : Test 함수의 2번 째 콜백이 promise 객체를 반환해야 합니다. 테스트 콜백이 프라미스 객체를 리턴하기 전에, fetchData의 resolve가 실행된다면 테스트가 이미 완료 되어버리고, then()구문이 실행되게 됩니다.

만약 개발자가 테스트 코드에서 반환되는 promise가 rejected 되길 예상한다면, .rejects 매쳐를 이용하세요. 이는 논리적으로 .resolves 매처에 정확히 반대 됩니다. 만약 resolves와 rejects를 동시에 쓴다면 테스트는 자동으로 실패 처리 됩니다.

Async / Await

여러분은 async와 await을 테스트에 사용하며, 비동기적인 코드를 테스트 할 수 있습니다. Async 키워드를 테스트 함수 앞에 작성 함으로써 테스트 전체를 동기적으로 테스트가 가능합니다.

test('the data is peanut butter', async () => {  
const data = await fetchData();  
expect(data).toBe('peanut butter');  
});

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

.resolves 와 .rejects 또한 async/await 패턴을 이용하여 사용 가능합니다.

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

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

이 경우, async/await 패턴은 문법적으로 매우 훌륭하고, 다른 방법들과 동일한 결과를 반환 합니다.

#JEST

반응형

'TDD > JEST' 카테고리의 다른 글

[JEST]snapshot test  (0) 2021.05.24
[JEST] Mock functions  (0) 2021.05.19
[JEST] Setup and  Teardown  (0) 2021.05.18
[JEST] Matcher 사용하기  (0) 2021.05.16
[JEST] 시작하기 설치 및 설정  (1) 2021.05.15
Comments