단위 테스트 검증

테스트명 짓기

export function add(a,b) {
  const sum = a + b;
  if (sum > 100) {
    return 100;
  }
  
  return sum;
}

//BAD test
test("50 +50은 100", () => {
  expect(add(50,50)).toBe(100);
)

test("70 + 80은 100", () => {
  expect(add(70,80)).toBe(100);
})
  • 테스트는 통과했지만 70 + 80이 100이 된다는 것은 이해할 수 없다.

  • 따라서 테스트 명을 함수 기능에 부합하는 더 적절한 이름을 변경해야 한다.

  • test 함수를 작성할 때 테스트 코드가 어떤 의도로 작성됐으며, 어떤 작업이 포함됐는지 테스트명으로 명확하게 표현해야다 한다.

에지 케이스와 예외 처리

  • 모듈을 사용할 때 실수 등의 이유로 예상하지 못한 입력값을 보낼 때가 있다.

  • 만약 모듈에 예외 처리를 했다면 예상하지 못한 입력값을 받았을 때 실행 중인 디버거로 문제를 빨리 발견할 수 있다.

타입스크립트로 입력값 제약 설정

  • 타입스크립트를 사용한다면 함수의 매개변수에 타입을 붙여 다른 타입의 값이 할당되면 실행하기 전에 오류를 발생시킨다.

  • 하지만 정적 타입을 붙이는 것만으로는 부족할 때가 있다.

  • 예를 들어 특정 범위로 입력값을 제한하고 싶을 때는 런타임에 예외를 발생시키는 처리를 추가해야한다.

예외 발생시키기

  • ex: add 함수에 매개변수 a,b는 0에서 100까지 숫자만 받을 수 있다는 조건을 추가해보자.

  • 타입만으로는 커버할 수 없다.

오류 메시지를 활용한 세부 사항 검증

  • 예외 처리용 매처인 toThrow에 인수를 할당하면 예외에 대해 더욱 상세한 내용을 검증할 수 있다.

  • Error 인스턴스를 생성하면서 메시지를 인수로 할당

  • 의도적으로 예외를 발생시키기도 하지만 의도치 않은 버그가 생겨서 발생할 때도 있다.

  • 의도했는지 아닌지 구분하기 위해 '의도한 대로 예외가 발생하고 있는가'라는 관점으로 접근하자.

instanceof 연산자를 활용한 세부 사항 검증

  • Error 클래스를 더욱 구체적인 상황에 맞춰 작성해보자.

    • 설계의 폭을 넓힐 수 있다.

  • Error 클래스를 상속받은 두 개의 클래스 HttpError, RangeError 로 생성된 인스턴스는 instanceof 연산자를 사용해서 다른 인스턴스와 구분할 수 있다.

  • 상속받은 클래스들을 활용해 입력값을 체크하는 함수를 작성해보자.

  • 기존 add 함수에서 a,b를 검증해서 예외를 발생시키는 부분을 checkRange 함수 한곳에서 처리할 수 있어서 더 좋은 코드가 된다.

  • toThrow 매처의 인수에는 메시지뿐만아니라 클래스도 할당이 가능하다.

  • 예외가 특정 클래스의 인스턴스인지 검증할 수 있다.

용도별 매처

  • 단언문은 테스트 대상이 기댓값과 일치하는지 매처로 검증한다.

진릿값 검증

  • toBeTruthy 는 참인값과 일치하는 매처

    • toBeFalsy 는 거짓인값과 일치하는 매처

  • 각 매처 앞에 not 을 추가하면 진릿값을 반전시킬 수 있다.

  • null 이나 undefinedtoBeFalsy 와 일치한다.

  • 하지만 null 인지 undefined 인지 검증하고 싶을 떄는 toBeNull 이나 toBeUndefined 를 사용

수치 검증

  • 등가 비교나 대소 비교 관련 매처를 사용

  • toBe, toEqual, toBeGreaterThan, toBeLessThen

  • 자바스크립트는 소수 계산에 오차가 있다.

    • 10진수인 소수를 2진수로 변환할 때 발생

    • 소수를 정확하게 계산해주는 라이브러리를 사용하지 않고 계산한 소숫값을 검증할때는 toBeCloseTo 매처를 사용한다.

    • 두 번째 인수로 몇 자릿수까지 비교할것인지 지정 가능

문자열 검증

  • 등가 비교 혹은 문자열 일부가 일치하는지 검증하는 toContain

  • 정규표현식을 검증하는 toMatch 같은 매처를 사용

  • 문자열 길이는 toHaveLength로 검증

  • stringContaining 이나 stringMatching 은 객체에 포함된 문자열을 검증할 때 사용한다.

  • 검증할 객체의 프로퍼티중 기댓값으로 지정한 문자열의 일부가 포함됐으면 테스트가 성공한다.

배열 검증

  • 배열에 원시형인 특정값이 포함됐는지 확인하고 싶다면 toContain

  • 배열 길이를 검증하고 싶을 때는 toHaveLength

  • 배열에 특정 객체가 포함됐는지 확인할 때는 toContainEqual

  • arrayContaining 을 사용하면 인수로 넘겨준 배열의 요소들이 전부 포함돼 있어야 테스트가 성공한다.

  • 두 매처 모두 등가 비교

객체 검증

  • 객체 검증은 toMatchObject 를 사용

  • 부분적으로 프로퍼티가 일치하면 테스트를 성공시키고 일치하지 않는 프로퍼티가 있으면 테스트 실패

  • 객체의 특정 프로퍼티가 있는지 검증할때는 toHaveProperty 를 사용

  • objectContaining 은 객체 내부 또는 다른 객체를 검증할 떄 사용함

  • 테스트 대상의 프로퍼티가 기댓값인 객체와 부분적으로 일치하면 테스트 성공

비동기 처리 테스트

  • 자바스크립트 프로그래밍에서 비동기 처리는 필수 요소이다.

  • 외부 API에서 데이터를 취득하거나 파일을 읽는 등 온갖 작업에서 비동기 처리가 필요하다.

Promise를 반환하는 방법

  • Promise 를 반환하면서 then 에 전달할 함수에 단언문을 작성하는 방법

  • wait 함수를 실행하면 Promise 인스턴스가 생성된다.

  • 해당 인스턴스를 테스트 함수의 반환값으로 리턴하면 Promise 가 처리 중인 작업이 완료될 떄까지 테스트 판정을 유예한다.

  • 두 번째 방법은 resolve 매처를 사용하는 단언문을 리턴하는 것

  • wait 함수가 resolve 됐을 때의 값을 검증하고 싶다면 첫번째 방법보다 간편하다.

async/await을 활용한 방법

  • 테스트 함수를 async 함수로 만들고 나서 함수 내에서 Promise가 완료될 때까지 기다리는 방법

  • resolves 매처를 사용하는 단언문도 await 로 대기시킬 수 있다.

  • 네 번째 방법은 검증값인 Promise가 완료되는 것을 기다린 뒤 단언문을 실행하는 것

  • 가장 간단한 방법

  • async/await 함수를 사용하면 비동기 처리가 포함된 단언문이 여럿일 때 한 개의 테스트 함수 내에서 정리할 수 있는 장점이있음

Reject 검증 테스트

  • 반드시 reject 되는 코드의 함수를 사용해 reject 된 경우를 검증하는 테스트를 작성

테스트 결과가 기댓값과 일치하는지 확인

  • 실수로 작성된 코드가 있을 때 실행하고 싶은 단언문에 도달하지 못한 채로 성공하며 종료된다.

  • 이와 같은 실수를 하지 않으려면 테스트 함수 첫 줄에 expect.assertions를 호출해야 한다.

  • 이 메서드는 실행되어야 하는 단언문의 횟수를 인수로 받아 기대한 횟수만큼 단언문이 호출됐는지를 검증한다.

  • 비동기 처리 테스트를 할 때는 첫 번째 줄에 expect.assertions 을 추가하면 사소한 실수를 줄일 수 있다.

  • 비동기 처리 테스트는 다양한 방식으로 작성할 수 있으니 자유롭게 선택하면 되지만 .resolves, .rejects 매처를 사용할 떄는 주의해야 한다.

  • 테스트가 성공한것이 아니라 (*주의)단언문이 한 번도 평가되지 않고 종료될 때에도 테스트는 성공한다.

  • 비동기 처리를 테스트할 때 테스트 함수가 동기 함수라면 반드시 단언문을 return 해야 한다.

  • 테스트에 따라서는 단언문을 여러 번 작성해야 할 때가 있는데 단언문을 여러번 작성하다 보면 return 하는 것을 잊기 쉽다.

  • 이같은 실수를 하지 않으려면 비동기 처리가 포함된 테스트를 할때 다음 과 같은 규칙을 갖고 접근해야 한다.

    • 비동기 처리가 포함된 부분을 테스트할 때 테스트 함수를 async 함수로 만든다.

    • .resolves, .rejects 가 포함된 단언문은 await 한다.

    • try-catch 문의 예외 발생을 검증할 때는 expect.assertions 를 사용한다.

Last updated