게으른개발너D

jest - 비동기 코드 테스트 본문

개발/JavaScript

jest - 비동기 코드 테스트

lazyhysong 2023. 10. 24. 21:55

1. callback

1. callback 패턴 이용

3초 후에 name 값을 넘겨주는 비동기 함수를 작성해 보자.

fn.js

const fn = {
  getName: (callback) => {
    const name = 'Mike';
    setTimeout(() => {
      callback(name);
    }, 3000);
  },
}
module.exports = fn;

callback를 매개변수로 받아서 callback으로 name을 첫번째 인수로 넘겨주는 함수를 작성하였다.

 

 

fn.test.js

const fn = require('./fn');

test("3초 후에 받아온 이름은 Mike이다.", () => {
  const callback = (name) => {
    expect(name).toBe('Mike');
  }
  fn.getName(callback);
});

getName함수를 호출하고 함수의 인수로 callback을 전달한다.

callback 함수의 내용은 name을 매개변수로 받은 후 expect로 name이 Mike인지 바로 확인하는 함수이다.

 

테스트는 통과하게 된다.

이상한 점은 비동기 함수로 3초 이후에 name을 확인하게 작성하였는데 test는 1ms만에 끝났다는 점이다.

 

실패하는 코드를 작성해 보자.

fn.test.js

test("3초 후에 받아온 이름은 Tom이다.", () => {
  const callback = (name) => {
    expect(name).toBe('Tom');
  }
  fn.getName(callback);
});

예상과 다르게 통과가 되었다.

 

아마 가장 많이 사용하는 비동기 패턴은 callback을 사용하는 방식일 것이다.

하지만 jest는 실행이 test 함수의 끝에 도달하게 되면 그대로 끝이난다. 그래서 예정되어있던 callback 함수가 실행되지 않는다.

 

이걸 해결하기 위해 test 함수에 done이라는 함수를 전달해 주면 된다.

 

 

2. done

done이 호출 되기 전까지 jest는 test를 끝내지 않고 기다리게 된다.

fn.test.js

test("3초 후에 받아온 이름은 Mike이다.", (done) => {
  const callback = (name) => {
    expect(name).toBe('Mike');
    done();
  }
  fn.getName(callback);
});

callback 함수가 실행되고 done이 실행되면 될 것이다.

결과는 이렇게 비동기 함수를 실행시켜 3초가 지난 후에 통과가 되었음을 알게된다.

 

만약 done 함수를 test 함수에서 전달은 받았는데 사용을 하지 않는다면 timeout으로 실패하게 된다.

5초동안의 timeout이 있고 그동안 응답이 없으면 실패로 간주하게 된다.

 

 

3. try catch

api 에러를 감지하고 싶다면 try catch 문으로 감싸주면 된다.

에러 함수를 작성해 보자.

fn.js

const fn = {
  getName: (callback) => {
    const name = 'Mike';
    setTimeout(() => {
      throw new Error('서버 에러..');
    }, 3000);
  }
}
module.exports = fn;

테스트 코드는 try catch로 감싸준다.

fn.test.js

test("3초 후에 받아온 이름은 Mike이다.", (done) => {
  const callback = (name) => {
    try {
       expect(name).toBe('Mike');
       done();
    } catch(error) {
       done();
    }
  }
  fn.getName(callback);
});

test를 실행시켜보면

이렇게 함수에서 작성한 서버 에러 라고 뜬다.

 

 

 

 

2. Promise

callback 패턴보단 Promise를 사용하는게 더욱 간결하고 명확하다.

 

1. Promise

3초 후에 나이를 리턴하는 함수를 하나 만들자.

fn.js

const fn = {
  getAge: () => {
    const age = 30;
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(age);
      }, 3000);
    });
  },
}

module.exports = fn;

이렇게 Promise를 리턴해주면 jest는 resolve 될때까지 기다려준다. 따라서 done 함수를 넘겨줄 필요가 없다.

fn.test.js

test("3초 후에 받아온 나이는 30", () => {
   fn.getAge().then((age) => {
      expect(age).toBe(30);
   });
})

결과는 또 1초만에 성공한 케이스로 나타난다.

테스트 코드가 잘못된 것이다.

 

Promise로 작성한 코드를 test할 땐 return을 해줘야한다.

그렇지 않으면 방금처럼 test가 그냥 종료된다.

test("3초 후에 받아온 나이는 30", () => {
   return fn.getAge().then((age) => {
      expect(age).toBe(30);
   });
})

 

2. resolves, rejects

더 간단하게 사용하고싶다면 Matcher를 사용하면 된다.

test("3초 후에 받아온 나이는 30", () => {
   return expect(fn.getAge()).resolves.toBe(30);
})

 

 

 

3. Async, Await

fn.test.js

test("3초 후에 받아온 나이는 30", async () => {
   const age = await fn.getAge();
   expect(age).toBe(30);
})

사용방법은 그냥 async await 사용방법과 같다.

async await에선 return을 사용하지 않아도 된다.

 

여기서도 마찬가지로 resolves, rejects matcher를 사용할 수 있다.

test("3초 후에 받아온 나이는 30", async () => {
   await expect(fn.getAge()).resolves.toBe(30);
})

 

 

 

 

 

 


출처

코딩앙마 (유튜브)

https://www.youtube.com/watch?v=snFRUjYR6j4

'개발 > JavaScript' 카테고리의 다른 글

jest - Matcher  (0) 2023.10.23
jest - 설치 및 튜토리얼  (0) 2023.10.23
[test] js test code 작성  (0) 2023.08.07
스코프(Scope)와 클로저(Closure)  (0) 2023.08.04
흐름제어 (Control Flow, Data Flow)  (0) 2023.08.04
Comments