Jest 사용법 - matcher

공식문서에 있는 예제를 통해 기본적인 사용법을 빠르게 익힌다. 따라서 모든 내용은 공식 문서 기반이며, 추후에 테스트를 많이 작성하면서 발생한 엣지 케이스를 이 내용에 덧붙여 추가할 예정이다.

테스트 예제

sum.js
export function sum(a, b) {
  return a + b;
}

Common Matchers

Jest에서는 "매처(matcher)"를 사용하여 다양한 값을 테스트 할 수 있다.

toBe()

원시 값(primitive value)을 비교하거나 객체 인스턴스의 참조 ID(referential identity of object instances)를 검사하는데 쓰인다.

test("adds 1 + 2 to equal 3", () => {
  expect(sum(1, 2)).toBe(3);
});

const person = {
  name: 'cob',
  age: 30
};

test("person has name", () => {
  expect(person.name).toBe('cob');
});

.toBe()는 부동 소수점과 사용하면 안된다. 이때는 대신 .toBeCloseTo()를 사용하자.

이유는 몰라도 되지만 굳이 한번 설명해 보자면, 이는 바이너리(binary) 값과 상관있다. 우리는 일반적으로 10진수를 사용하지만, 바이너리에서는 0과 1의 연속으로 이루어진 2진수로 표시된다. 컴퓨터는 10진수더라도 10진수가 아닌 바이너리로 계산하고 다시 10진수로 결과를 반환한다. 하지만 이 결과는 때로는 정확하지 않으며, 여기서 부동 소수점 반올림 오류가 발생하는 이유는 반복 소수점(Recurring Decimal) 개념과 관련 있다. (1/3 = 0.333... )

10진법의 소인수는 2와 5이므로 1/2, 1/4, 1/5, 1/8, 1/10은 깔끔하게 표현된다. 실제 브라우저 콘솔에서 테스트 해보더라도 위의 수의 덧셈은 우리가 아는 정답의 결과가 나오는걸 확인할 수 있다. 반 나머지 1/3, 1/6, 1/7, 1/9는 반복 소수점이다.

2진법의 소인수는 2이기 때문에 1/2만 명확하게 표현할 수 있으며 다른 값은 반복 소수점이 된다. 즉 0.1과 같은 10진수는 10진수를 사용하면 10진수의 단일 숫자로 표시할 수 있지만, 2진수로는 표시할 수 없는 것이다.

자바스크립트는 모든 숫자를 64비트의 부호있는 부동 소수점 값으로 저장하며, 값을 저장할 공간이 충분하지 않으면 최하위 숫자가 반올림된다(IEEE 754). 이는 자바스크립트에만 국한되는 문제는 아니며, 이미 정밀도를 요구하는 곳에서는 다른 해결책이 많이 나와있다.

이것은 오류가 아니라 컴퓨터가 숫자를 다루는 방식이다. 오해하지 말자.

toEqual()

일치하는 object 값, 참고로 숫자 값에 관해서는 toBe와 동일하다.

test("object assignment", () => {
  const data = { one: 1 };
  data["two"] = 2;
  expect(data).toEqual({ one: 1, two: 2 });
});

Truthiness 관련 matcher

test("null", () => {
  const n = null;
  expect(n).toBeNull();
  expect(n).toBeDefined();
  expect(n).not.toBeUndefined();
  expect(n).not.toBeTruthy();
  expect(n).toBeFalsy();
});

test("zero", () => {
  const z = 0;
  expect(z).not.toBeNull();
  expect(z).toBeDefined();
  expect(z).not.toBeUndefined();
  expect(z).not.toBeTruthy();
  expect(z).toBeFalsy();
});4

toBeTruthy(), toBeFalsy() vs toEqual()?

자바스크립트에는 원시 boolean 타입 말고도 내재된(inherent) boolean 값이 있고, 보통 truthy와 falsy로 표기한다. false, "", null, undefined, NaN은 falsy이며, 그 외의 모든 값은 truthy이다. falsy한 값이나 truthy 값을 테스트 하는게 목적이 아니라, 정확한 불린 값으로 비교하고 싶다면 toEqual 매처를 사용하는 것이 좋다.

Number 관련 matcher

test("two plus two", () => {
  const value = 2 + 2;
  expect(value).toBeGreaterThan(3);
  expect(value).toBeGreaterThanOrEqual(3.5);
  expect(value).toBeLessThan(5);
  expect(value).toBeLessThanOrEqual(4.5);

  // toBe와 toEqual는 숫자 에 대해서는 똑같다.
  expect(value).toBe(4);
  expect(value).toEqual(4);
});

부동 소수점 동등성의 경우 테스트가 작은 반올림 오류에 의존하는 것을 원하지 않기 때문에, toEqual 대신 toBeCloseTo를 사용한다.

test("adding floating point numbers", () => {
  const value = 0.1 + 0.2;
  // expect(value).toBe(0.3);  // 반올림 오류로 동작하지 않는다.
  expect(value).toBeCloseTo(0.3);
});

String

문자열의 경우 정규식을 사용하여 확인할 수 있다.

test("there is no I in team", () => {
  expect("team").not.toMatch(/I/);
});

test('but there is a "stop" in Christoph', () => {
  expect("Christoph").toMatch(/stop/);
});

toContain()

어떤 문자열이 다른 문자열 내부에 포함되어 있는지 혹은 어떤 배열이 특정 엘리먼트를 포함하고 있는지 확인할 수 있다. 참고로 배열의 항목에 포함되어 있는지에 대한 테스트는 엄격한 동등성 검사(===)를 사용한다.

describe('toContain 매처는', () => {
  test('문자열 내부의 문자열을 포함하는지 확인 할 수 있다', () => {
    expect('jacob').toContain('cob')
  });
  test('배열의 엘리먼트를 확인할 수 있다.', () => {
    expect(['cob', 0]).toContain(0)
    expect(['cob', 0]).not.toContain('0')
  });
})

Array and iterables

배열과 이터러블에 특정 항목이 포함되었는지 확인하기 위해 toContain을 사용한다.

const shoppingList = [
  "diapers",
  "kleenex",
  "trash bags",
  "paper towels",
  "beer"
];

test("the shopping list has beer on it", () => {
  expect(shoppingList).toContain("beer");
  expect(new Set(shoppingList)).toContain("beer");
});

Exceptions

특정 함수가 호출될때 오류가 발생하는지 테스트할 수 있다.

test("compiling android goes as expected", () => {
  expect(() => compileAndroidCode()).toThrow();
  expect(() => compileAndroidCode()).toThrow(Error);

  // 정확한 오류 메시지나 정규식을 사용할 수 있다.
  expect(() => compileAndroidCode()).toThrow("you are using the wrong JDK");
  expect(() => compileAndroidCode()).toThrow(/JDK/);
});

예외를 발생시키는 함수는 래핑 함수 내에서 호출되어야 한다.

expect.assertions(number)

테스트 중에 특정 개수의 어설션이 호출되는지 확인한다. 종종 이것은 비동기 코드를 테스트 할 때 유용하여 콜백의 어설션이 실제로 호출되었는지 확인한다.

test('doAsync will call both callbacks', () => {
  expect.assertions(2);
  function callback1(data) {
    expect(data).toBeTruthy();
  }
  function callback2(data) {
    expect(data).toBeTruthy();
  }

  doAsync(callback1, callback2);
});

Last updated