Test Utility - Enzyme

Test Utility - Enzyme

이번장은 앞장에서 설명한 Test FrameWork: Jest에 이어서
React를 위한 자바스크립트 테스트 유틸리티인 Enzyme(엔자임)을 설명하려고 합니다.

Enzyme이란?

Enzyme은 airbnb에서 개발한 React용 컴포넌트 테스트 플러그인입니다.
컴포넌트를 얖게(shallow) 렌더링해서 테스트 해 볼 수 있고, 전체 DOM을 불러와 확인 할 수도 있습니다.
또한 그 형태가 jQuery 형태로 컴포넌트를 조회할 수 있기 때문에, 컴포넌트 테스트로는 Enzyme이 매우 유용합니다.

사용법

우선 npm으로 enzyme & enzyme-adapter-react-16 를 설치합니다.

1
npm install --save-dev enzyme enzyme-adapter-react-16

enzyme-adapter-react-16은
Enzyme이 react 16버전과 react 15버전에서 다르게 동작하기 때문에 enzyme-adapter-react-16 을 사용하여
react 16을 사용하고 있음을 알려주는 서드파티 입니다.

자 이제 앞장(Test FrameWork: Jest)에서 작성했던 Counter.test.jsx 테스트 코드에 enzyme을 적용해보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import React from 'react';
import renderer from "react-test-renderer";
import Counter from './index';

describe('Counter', () => {
let component = null;

it('renders correctly', () => {
component = renderer.create(<Counter />);
});

it('matches snapshot', () => {
expect(component).toMatchSnapshot();
});

it('increases correctly', () => {
component.getInstance().onIncrease();
expect(component.getInstance().state.value).toBe(2);
expect(component).toMatchSnapshot();
});

it('decreases correctly', () => {
component.getInstance().onDecrease();
expect(component.getInstance().state.value).toBe(1);
const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
});

위의 테스트 코드에 Enzyme을 적용하면
이제는 react-test-renderer 대신 Enzyme의 shallow를 사용하게됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import React from 'react';
import { shallow, configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import Counter from './index';
configure({ adapter: new Adapter() });

describe('Counter', () => {
let component = null;

it('renders correctly', () => {
component = shallow(<Counter />);
});

it('matches snapshot', () => {
expect(component).toMatchSnapshot();
});

it('increases correctly', () => {
component.instance().onIncrease();
expect(component.state().value).toBe(2);
expect(component).toMatchSnapshot();
});

it('decreases correctly', () => {
component.instance().onDecrease();
expect(component.state().value).toBe(1);
expect(component).toMatchSnapshot();
});
});

Enzyme에서 configure를 제외한다면 크게는 3가지 메서드가 존재하고, 그 메서드는 shallow, mount, render 입니다.

  1. shallow: 간단한 컴포넌트를 메모리에 렌더링합니다. ( 단일 컴포넌트를 테스트할 때 유용합니다. )
  2. mount: HOC나 자식 컴포넌트 까지 전부 렌더링합니다. ( 다른 컴포넌트와의 관계를 테스트할 때 유용합니다. )
  3. render: 컴포넌트를 정적인 html로 렌더링합니다. ( 컴포넌트가 브라우저에 붙었을 때 html로 어떻게 되는지 판단할 때 사용합니다.)

※ shallow 와 mount 두 API는 유사한 동작을 합니다.
그러나 mount가 좀 더 실제에 가깝게 동작을 합니다.
공식문서에는 테스트할 컴포넌트가 DOM API를 사용하거나 라이프사이클 훅 을 모두 활용할때 mount API를 사용하는것을 권장하고 있습니다.

특히 라이프 사이클 훅 관련하여 shallow와 mount는 차이점이 있습니다.
mount API는 모든 라이프사이클 훅이 호출되고,
shallow API는 componentDidmount 와 componentDidUpdate를 제외한 라이프사이클 훅이 호출된다는 점입니다.
이러한 차이점을 유의하여 필요에 따라 API를 사용하시면 됩니다.

위의 코드가 Enzyme을 적용한 코드인데
이렇게만 보면 굳이 왜? react-test-renderer 대신 Enzyme의 shallow를 사용하지? 라고 생각할 수 있을 것 입니다.

하지만
Enzyme을 사용하면 저희는 DOM이벤트를 시뮬레이트 해 볼 수 있습니다.
DOM이벤트를 시뮬레이트한다? 필자는 글로봐서는 감이 오지 않았습니다.

Enzyme API중 simulate를 사용하게 되는 것 인데,
위의 Enzyme 적용 테스트 코드 내용 중

1
component.instance().onIncrease()

처럼 함수를 실행하는 것이 아니라

1
component.find('.increaseButton').simulate('click');

처럼 실제로 카운트를 증가시키는 버튼을 마우스를 클릭하는 이벤트를 시뮬레이션 할 수 있게 되고,
아래의 테스트 코드처럼 테스트 할수 있게 됩니다.

1
2
3
4
5
it('increases correctly', () => {
component.find('.increaseButton').simulate('click');
expect(component.state().value).toBe(2);
expect(component).toMatchSnapshot();
});

이렇게 Enzyme을 사용하면 특정 DOM에 이벤트를 시뮬레이트 할 수 도 있고, 그 외에도 수 많은 기능들이 있습니다.
나머지 수많은 기능들은 Enzyme 공식 홈페이지를 참고하여 필요에 따라 사용하시길 바랍니다.

마지막으로 Jest와 Enzyme을 같이 사용하면 스냅샷이 보기 힘든 형태로 나오게 되는데 이 부분은
pakage.json에

1
2
3
4
5
"jest": {
"snapshotSerializers": [
"enzyme-to-json/serializer"
]
}

를 추가해주시면 됩니다.


Comments: