오늘 읽은 범위

4장 목 객체

책에서 기억하고 싶은 내용을 써보세요.

목 객체 유형

  1. 스텁
    • 주로 대역으로 사용한다.
    • 의존중인 컴포넌트에 테스트하기 어려운부분이 있을 때 사용한다. (ex. 웹 api 호출)
  2. 스파이
    • 주로 기록하는 용도로 사용한다.
    • 테스트 대상 외부의 출력을 검증할 때 사용한다. (ex. 콜백 함수)

목 모듈을 활용한 스텁

jest.mock(modulePath, factoryFn)

  • 함수가 들어있는 모듈을 통째로 mocking
  • jest.mock(테스트할 모듈, 어떻게 mock할지 정의하는 함수)
jest.mock('./greet', () => {
  return {
    greet: jest.fn(() => 'Hi!'),
    bye: jest.fn(() => 'See ya!'),
  };
});
 
import { greet, bye } from './greet';
 
test('custom mock with factory', () => {
  expect(greet('Alice')).toBe('Hi!');
  expect(bye('Bob')).toBe('See ya!');
});

웹 API 스텁

jest.spyOn(object, methodName)

  • jest.spyOn(테스트할 객체, 테스트할 함수 이름)
    • mockResolvedValueOnce() : 비동기 모의 함수가 resovled일때 지정한 값을 한번만 지정
    • mockRejectedValueOnce() : 비동기 모의 함수가 rejected일때 지정한 값을 한번만 지정
test('성공 시', async () => {
	jest.spyOn(Fetchers, "getMyProfile").mockResolvedValueOnce({
		name: "jessie",
	});
	await expect(getGreet()).resolves.toBe("Hello, jessie!");
})
 
test('실패 시', async () => {
	jest.spyOn(Fetchers, "getMyProfile").mockRejectedValueOnce(httpError);
	await expect(getGreet()).rejects.toMatchObject({
		err : {message: "internal server error"}, 
	})
})

목 함수를 사용하는 스파이

  • toBeCalled() : 실행됐는지 검증
  • toHaveBeenCalledTimes() : 실행 횟수 검증
  • toHaveBeenCalledWith() : 실행 시 인수 검증
test("목 함수는 실행 시 인수를 기록한다.", () => {
	const mockFn = jest.fn();
	function greet(message: string) {
 		mockFn(message);
	}
	greet("hello");
	expect(mockFn).toHaveBeenCalledWith("hello");
})

현재 시각에 의존하는 테스트

  • 테스트 결과가 실행 시각에 의존하게 되는 경우, 테스트 실행 환경의 현재 시각을 고정하면 언제라도 같은 실행 결과를 얻을 수 있다.

궁금한 내용이 있거나, 잘 이해되지 않는 내용이 있다면 적어보세요.

  1. 스텁과 스파이의 개념 및 비교
구분스텁스파이
목적미리 정해둔 값을 돌려주기만 한다.호출 기록이나 파라미터를 기억하고 필요하면
동작도 정의 할 수 있다.
관심사결과값호출 정보와 결과값
테스트 용도특정 상황을 시뮬레이션호출 여부, 횟수, 전달된 값 검증
  1. mocking이 적용되는 이유
    • jest.spyOn(Fetchers, "getMyArticles")Fetchers 객체의 getMyArticles 프로퍼티 자체를 스파이/목 함수로 갈아끼우는 사이드 이펙트를 일으킨다. 이미 전역적으로 바꿔치기된 상태이기 때문에 굳이 mockGetMyArticles 호출의 리턴값을 변수에 안담아도 전부 목 버전을 쓰게 되는 것.
function mockGetMyArticles(status = 200) {
  if (status > 299) {
    return jest
      .spyOn(Fetchers, "getMyArticles")
      .mockRejectedValueOnce(httpError);
  }
  return jest
    .spyOn(Fetchers, "getMyArticles")
    .mockResolvedValueOnce(getMyArticlesData);
}
 
test("지정한 태그를 포함한 기사가 한 건도 없으면 null을 반환한다", async () => {
  mockGetMyArticles();
  const data = await getMyArticleLinksByCategory("playwright");
  expect(data).toBeNull();
});