Jest 사용법 (5) - 비동기 코드(Async Code)

modolee·2020년 9월 24일
3
post-thumbnail
  • 비동기 코드를 테스트 할 때는 언제 다음 테스트 코드로 넘어가야 되는지를 알려줘야 됨.
  • Jest에서는 이런 경우를 다루는 여러가지 방법이 있음

Callbacks

callback을 사용하는 코드

const fetchDataCallback = (cb) => {
  setTimeout(() => {
    console.log("wait 3.5 sec.");
    cb('peanut butter');
  }, 3500);
};

잘못 된 테스트 방법

  • callback 함수가 호출되지 않고 test 종료
  • 잘못 된 결과가 나와도 테스트가 통과 됨
// Don't do this!
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');
  });
});
profile
기초가 탄탄한 백엔드 개발자를 꿈꿉니다.

0개의 댓글