Dog foot print

[JEST]snapshot test 본문

TDD/JEST

[JEST]snapshot test

개 발자국 2021. 5. 24. 22:31

Snapshot Test

Snapshot test란 UI가 바뀌지 않았다는 것을 증명하는 유용한 도구이다.

snapshot 은 UI컴포넌트를 렌더링 한 후, 이를 다음 테스트와 함께 저장된 스냅샷과 비교하며 테스트가 진행된다. snapshot테스트는 두개의 스냅샷이 일치 하지 않은 경우, 실패하게 됩니다. 이 경우, 새롭게 적용한 컴포넌트의 UI가 의도치 않게 변경되었거나, 컴포넌트가 버전이 변경되었음을 시사합니다.

Snapshot Testing with Jest

모든 App의 그래픽 UI를 렌더하는 대신에, 테스트 렌더러를 사용하여, React 트리를 빠르게 생성 할 수 있습니다.

import React from 'react';
import renderer from 'react-test-renderer';
import Link from '../Link.react';

it('renders correctly', () => {
  const tree = renderer
    .create(<Link page="http://www.facebook.com">Facebook</Link>)
    .toJSON();
  expect(tree).toMatchSnapshot();
});

위의 테스트를 실행하게 되면 제스트는 다음과 같은 스냅샷 파일을 만듭니다.

exports[`renders correctly 1`] = `
<a
  className="normal"
  href="http://www.facebook.com"
  onMouseEnter={[Function]}
  onMouseLeave={[Function]}
>
  Facebook
</a>
`;

스냅 샷을 통해 만들어진 파일은 코드 변경과 함께 커밋되고, 리뷰가 진행될 때 일부로 검토되어야 합니다. 제스트는 pretty-format을 사용하여, 스냅샷을 사람이 읽을 수 있도록 만들어 줍니다. 테스트가 진행 될 때, 제스트는 기존 스냅샷 파일과 렌더링 된 파일의 스냅샷을 비교합니다. 만약 두개의 스냅샷이 일치한다면, 테스트는 통과 될 것이며, 그렇지 않다면 코드에 버그가 존재하는 것입니다. 그렇기에, 개발자는 컴포넌트 내부에 존재하는 버그를 고치거나, 스냅샷을 업데이트 해야 합니다.

Note : 스냅샷은 렌더링한 데이터에 한하여, 범위가 지정됩니다. 위의 예제에서는 page props로 전달된 Link 컴포넌트가 예시입니다. 만약 App.js 파일에서 Link 컴포넌트를 사용하고 다른 프롭스를 전달하여 다르게 렌더링 되어도, 테스트 케이스에서 작성된 검사 기준이 달라지지 않았다면 테스트는 성공 할 것입니다.

Note : 스냅샷 테스트의 작동 구조나 왜 우리가 이것을 만들었는지 더 자세한 정보가 필요하다면, release blog를 확인하세요.

Updating Snapshot

버그가 발생하면, 쉽게 그 지점을 확인 할 수 있습니다. 만약 버그가 발생했다면, 해당 이슈를 고쳐 스냅샷 테스트가 통과되게 해야합니다. 이제 우리는 구현하는 동안 변경이 일어 났을 때 스냅샷 테스트가 실패가 난다면 어떻게 해야 할 지 의논 해 봅시다 .

가능한 상황 중 Link컴포넌트의 page props를 변경 했다고, 가정하며 예시를 봅시다.

// Updated test case with a Link to a different address
it('renders correctly', () => {
  const tree = renderer
    .create(<Link page="http://www.instagram.com">Instagram</Link>)
    .toJSON();
  expect(tree).toMatchSnapshot();
});

이 테스트 코드는 위의 테스트 코드와 동일하지 않아, 실패할 것입니다. 그리고 다음과 같이 로그를 생성합니다.


우리가 컴포넌트의 주소를 변경 함으로써 컴포넌트가 예상가능한 변경이 되었습니다. 우리의 스냅샷 테스트는 새롭게 변경된 컴포넌트에 맞춰 스냅샷이 업데이트 되지 않았기 때문에, 에러를 발생 시킵니다.

이것을 해결하기 위해, snapshot 파일을 생성해야 합니다. 아래의 명령어로 스냅샷을 업데이트 시킬 수 있습니다.

$ jest --updateSnapshot

만약 더 작은 명령어를 원한다면 -u 명령어를 통해서, 동일한 효과를 볼 수 있습니다. 이 명령어는 새롭게 스냅샷을 만들어 내며, 변경된 테스트 케이스에 맞춰 성공하게 될 것 입니다. 스냅샷을 업데이트 하는 행위는 신중하게 생각해야 합니다. 만약 스냅샷 테스트에서 실패가 발생한다면, 스냅샷을 업데이트 하는 것이 아닌, 혹여 모르는 버그를 고치고 충분한 이유로 인해서 기존 스냅샷이 실패가 발생한다면 스냅샷을 업데이트 해야 합니다.

--testNamePattern 플래그를 이용하여, 다시 생성되는 스냅샷 테스트 생성을 제한 할 수 있습니다.

Interactive Snapshot Mode

watch mode를 통해서, 지속적으로 스냅샷 테스트를 업데이트 할 수 있습니다.

만약 Interactive snapshot Mode를 실행하고 있다면, 지속적으로 실패하는 테스트와 스냅샷을 비교 할 것입니다.

만약 종료된다면, 다음과 같이, watch mode이전의 상황으로 돌아가기전 요약 로그를 제공합니다.

Inline Snapshots

snapshot파일은 inline snapshot의 외부 확장 입니다. 동일한 내용을 포함하지만, snapshot 파일은 inline snapshot과 달리 자동으로 만들어 준다는 점에서 차이를 빚습니다. 다만 snapshot 을 찍었을 때, 이는 제스트가 자동으로 만들어주기 때문에, 정확한 값을 통해서 스냅샷 비교를 하기 어려울 수 있습니다.

Example :

먼저 .toMatchInlineSnapshot()을 전달인자 없이 호출 해보세요 .

it('renders correctly', () => {
  const tree = renderer
    .create(<Link page="https://prettier.io">Prettier</Link>)
    .toJSON();
  expect(tree).toMatchInlineSnapshot();
});

이후 제스트를 실행하면, 트리가 평가되고, 스냅샷을 제대로 작성하라고 메세지를 전달 할 것입니다.

it('renders correctly', () => {
  const tree = renderer
    .create(<Link page="https://prettier.io">Prettier</Link>)
    .toJSON();
  expect(tree).toMatchInlineSnapshot(`
<a
  className="normal"
  href="https://prettier.io"
  onMouseEnter={[Function]}
  onMouseLeave={[Function]}
>
  Prettier
</a>
`);
});

--updateSnapshot모드를 통해서 스냅샷을 업데이트 할 수 있습니다.

Property Matcher

스냅샷 테스트에 필드가 존재하는 경우가 있습니다. 이 경우, snapshot에 필드를 담으려고 하면, 항상 실패가 발생합니다.

it('will fail every time', () => {
  const user = {
    createdAt: new Date(),
    id: Math.floor(Math.random() * 20),
    name: 'LeBron James',
  };

  expect(user).toMatchSnapshot();
});

// Snapshot
exports[`will fail every time 1`] = `
Object {
  "createdAt": 2018-05-19T23:36:09.816Z,
  "id": 3,
  "name": "LeBron James",
}
`;

이런 경우, 제스트는 any 타입을 확인하는 비대칭 matcher 를 제공합니다. 이 matcher는 테스트를 진행하기 전에, 스냅샷에 값을 저장합니다.

it('will check the matchers and pass', () => {
  const user = {
    createdAt: new Date(),
    id: Math.floor(Math.random() * 20),
    name: 'LeBron James',
  };

  expect(user).toMatchSnapshot({
    createdAt: expect.any(Date),
    id: expect.any(Number),
  });
});

// Snapshot
exports[`will check the matchers and pass 1`] = `
Object {
  "createdAt": Any<Date>,
  "id": Any<Number>,
  "name": "LeBron James",
}
`;

Any가 주는 값은 스냅샷에서 생성된 값과 동일합니다.

it('will check the values and pass', () => {
  const user = {
    createdAt: new Date(),
    name: 'Bond... James Bond',
  };

  expect(user).toMatchSnapshot({
    createdAt: expect.any(Date),
    name: 'Bond... James Bond',
  });
});

// Snapshot
exports[`will check the values and pass 1`] = `
Object {
  "createdAt": Any<Date>,
  "name": 'Bond... James Bond',
}
`;

#jest

반응형

'TDD > JEST' 카테고리의 다른 글

[JEST] Mock functions  (0) 2021.05.19
[JEST] Setup and  Teardown  (0) 2021.05.18
[JEST] 비동기 코드 테스트  (0) 2021.05.16
[JEST] Matcher 사용하기  (0) 2021.05.16
[JEST] 시작하기 설치 및 설정  (1) 2021.05.15
Comments