tdd

스냅샷 테스트

UI 테스트와 스냅샷 테스트

여러 부분에서 큰 장점이 없으므로 정말 특별한 케이스가 아니면 스냅샷 테스트 작성 자체를 권장하지 않는다.

프론트앤드 테스트는 기능 검증 이외에도 스타일이나 레이아웃이 올바르게 렌더링 되는지 시각적인 검증을 해야한다.

스냅샷 테스트는 컴포넌트 뿐만 아니라 일반 함수의 결과도 직렬화 하여 기록한 후 비교 검증하는 것이 가능하다.

vitest에서 스냅샷을 테스트 할 때는 toMatchSnapshots()oMatchInlineSnapshots() Matcher를 사용하여 실행할 수 있다.

  • toMatchSnapshots() : 스냅샷 기록을 별도 파일로 관리
  • toMatchInlineSnapshots() : 스냅샷 기록을 테스트 파일 내에서 관리

스냅샷 테스트

  1. 대상 컴포넌트를 렌더링
  2. 컴포넌트의 DOM을 직렬화해 스냅샷으로 기록
  3. 기존 스냅샷과 새 스냅샷 비교
  4. 기존 스냅샷과 현재 스냅샷이 동일한 경우 테스트 통과
  5. 기존 스냅샷과 현재 스냅샷이 다른 경우 변경 사항 확인
  • 의도한 변경일 경우 스냅샷 업데이트
  • 의도한 변경이 아닌 경우 잘못된 부분을 찾아 수정

사용 방법 - 컴포넌트에 대한 스냅샷 테스트

리액트 테스팅 라이브러리의 렌더링 결과로 반환되는 요소 중 container 프로퍼티를 사용하면 렌더링된 돔 구조를 div 블럭으로 감싼 결과를 얻을 수 있다.


// 테스트 실행 전
it('스냅샷 테스트', async() => {
	const { container } = await render(<PageTitle/>);

	expect(container).tomatchInlineSnapshot();
})

// 테스트 실행 후
it('스냅샷 테스트', async () => {
  const { container } = await render(<PageTitle />);

  expect(container).toMatchInlineSnapshot(`
    <div>
      상품 리스트
    </div>
  `);
});

이때 테스트를 실행하면 toMatchInlineSnapshot() 안에 문자열 형태로 직렬화되어 스냅샷이 추가된다.

여기서 컴포넌트의 일부를 변경한 뒤 다시 테스트를 실행하면 실패한다.

만약 변경된 부분이 의도한 것이라면 u를 눌러 스냅샷을 최신 스냅샷으로 업데이트 할 수 있다.

의도한 변경 사항이 아닌 경우 잘못된 부분을 찾아 수정하면 된다.

사용 방법 - 유틸 함수에 대한 스냅샷 테스트

객체 내에 굉장히 많은 프로퍼티를 검증하는 테스트가 필요할 때 스냅샷 테스트를 사용하면 유용하다. 모든 프로퍼티의 기대값을 직접 입력하지 않아도 빠르게 테스트를 작성하여 검증할 수 있기 때문이다.


describe('util 단위 테스트', () => {
	// 원본
	it('단일 인자로 전달된 키의 값을 객체에 담아 반환한다', () => {
    const obj = {
      a: 'A',
      b: { c: 'C' },
      d: null,
    };

    expect(pick(obj, 'a')).toEqual({ a: 'A' });
  });

	// 스냅샷 테스트
  it('단일 인자로 전달된 키의 값을 객체에 담아 반환한다(snapshots)', () => {
    const obj = {
      a: 'A',
      b: { c: 'C' },
      d: null,
    };

    expect(pick(obj, 'a')).toMatchInlineSnapshot();
  });
})

스냅샷 테스트의 장단점

  • 간단하고 빠르게 컴포넌트 UI를 검증할 수 있다
  • 스냅샷 결과를 일관된 기준으로 관리하기 어렵다
  • 검증의 신뢰성에 대해서 명확한 한계점이 존재한다

스냅샷 테스트의 한계점

  • JS DOM에서의 스냅샷은 단순히 DOM 트리를 직렬화하여 문자열로 출력한 것이기 때문에 이 결과만 보고 브라우저에 올바르게 렌더링 되는지에 대해서는 알 수 없다.
  • 간단한 컴포넌트가 아니라 DOM 구조가 복잡한 컴포넌트를 대상으로 스냅샷 테스트를 한다면 스냅샷 결과만 몇십 줄이 넘어가는 경우도 많다.
  • 스냅샷 업데이트가 필요한 경우 개발자가 직접 업데이트 해야 하므로 일관된 결과를 보장할 수 없다.
  • 실제 UI의 스타일 변경 사항을 알아차릴 수 없다.
  • TDD를 도입하기에 적합하지 않다.

한계점 해결 방법

  • 일반 코드처럼 관리하기
  • 스냅샷 단위를 작게 잡고 너무 큰 단위로 스냅샷을 검증하지 않기
  • eslint의 no-large-snapshots 를 사용해 최대 스냅샷 길이를 정하기