brunch

You can make anything
by writing

C.S.Lewis

프로젝트에 테스팅 도입하기

삽질의 기억

안녕하세요. 플랫폼 개발팀에서 프론트 개발을 하고 있는 엘리엇입니다.

최근에 파트너스 프로젝트에 react-testing-libarary를 활용하여 테스트를 도입하여 소개하고자 합니다.



테스트를 도입하게 된 이유


Side Effect 관리의 어려움

파트너스 프로젝트는 user가 입력해야 하는 Form들이 매우 많습니다. 그리고 user들이 어떤 것을 입력했는지에 따라서 UI를 다르게 보여주어야 하는 경우가 많습니다.

이렇게 상호 의존적이 UI들이 많아질 수록 개발 단계에서 컨트롤 하기가 굉장히 어렵고, 수정이 있어야 하는 상황에서 어떤 Side-Effect가 있을지 예상이 불가한 상황이었습니다.


실제로 파트너스의 매뉴관리 파트를 개편하였을 때 QA과정에서의 수정이 또 다른 문제를 야기하여 그것을 다시 수정해야 하는 문제가 있었습니다. 이런 상황을 겪고 나니, 테스팅을 통해 사전에 Side Effect를 감지하고 미리 대응할 수 있으면 좋겠다는 생각을 하였습니다.


예측 불가능한 Javascript의 보완

Javascript는 런타임에 동적으로 타입을 체크합니다. 따라서 실제로 실행을 해보아야 에러를 확인할 수 있습니다. 이러한 문제를 보완하기 위해서는 Typescript를 사용하는 경우가 많지만 현재 파트너스 프로젝트에서는 Typescript를 사용하고 있지 않기 때문에 개발 단계에서 에러를 감지하는 데 한계가 있습니다. 테스트 코드로 이러한 문제를 어느 정도 보완하면 좋겠다는 생각을 하였습니다.



테스팅 컨셉


user가 사용하는 최종 UI를 검증한다.

이번 테스트의 목적은 user의 액션에 따른 UI변화가 예상대로 잘 흘러가고 있는지를 체크함에 있습니다. 따라서 컴포넌트의 내부적인 데이터의 흐름을 검증할 필요가 없습니다. 컴포넌트 내부의 로직을 정밀하게 검증을 하면 좋겠지만, 이럴 경우 업데이트가 있고 리팩토링을 할 때마다 테스트 코드를 수정해야 하는 리소스가 있을 것입니다.


User 컴포넌트에서는 "열기" 버튼을 클릭했을 때, user 정보가 담긴 Modal을 보여주어야 합니다.


위와 같은 상황에서 Modal Component에 user data가 잘 넘어갔는지, 그것을 state로 처리했는지, 어떤 state를 사용했는지 검증하지 않습니다.

단지 user는 "열기" 버튼을 클릭했고 최종화면에서 user 정보가 담긴 UI가 렌더링 되었는지 확인하면 됩니다.


Page 전체를 렌더링하여 테스팅을 진행한다.

테스트를 도입하는 이유에서도 설명했지만 이번 테스트에서 검증하고자 하는 것을 최종 UI이고 상호 의존적인 컴포넌트들이 통합된 상태로 잘 작동하는지를 확인하는 것입니다. 따라서 user의 입장에서 볼 수 있는 모든 컴포넌트를 렌더링 시켜야 정확하게 테스트를 할 수 있을 것입니다.

각각의 컴포넌트는 잘 작동하지만 이들이 서로 합쳐져서 작동할 때 문제가 발생할 수 있기 때문입니다.



테스팅 라이브러리의 선택


React를 테스팅하는 라이브러리들은 많습니다. 그 중에 "react-testing-library"를 사용하였습니다. 그 이유는 위에서 언급한 테스팅 컨셉과 가장 잘 맞았기 때문입니다.


기존에 enzyme과 같은 라이브러리는 테스팅하고자하는 DOM을 잡아서 제대로 렌더링 되었는지를 테스팅하는데 유리했습니다. 하지만 react-testing-library는 DOM를 정확히 확인하기보다는 UI위주로 검증을 합니다.


react-testing-library의 API들을 보면  getByText 와 같이 DOM을 지칭하지 않고 최종 결과물로 판단하려는 목적인 명확이 드러납니다. user가 확인하는 text를 확인하는 API인 것입니다.



테스트 환경설정

파트너스 프로젝트는 React + Next.js로 기본 프레임워크를 구성하였고, Redux 스토어를 사용합니다.

위와 같은 환경에서 테스트 환경을 세팅한 과정을 설명하겠습니다.


패키지 설치

- @testing-library/react

- @testing-library/jest-dom

- jest

- jsdom : 브라우저 환경에서 테스트가 동작하도록 세팅합니다.

- msw : 가상의 api 서버를 만들어서 mock data를 받을 수 있도록 세팅합니다.


Jest 설정

jest.config.js를 root directory에 생성하고 config 객체를 export 하면 테스트가 동작에 대한 설정을 지정할 수 있습니다.

실제 설정에 사용한 Key들이 어떤 역할을 하는지 설명 드리겠습니다. 더 자세한 내용은 문서 링크를 첨부하겠습니다.

https://jestjs.io/docs/configuration  

testPathIgnorePatterns(string[]): 테스트에 제외될 폴더나 파일을 패턴 형태로 지정할 수 있습니다. 환경설정 파일이나 테스트하고 싶지 않은 파일이나 폴더를 지정하여 테스트에서 제외시킬 수 있습니다.

    testMatch(string[]): 테스트를 포함하는 파일명을 정규식 형태로 지정할 수 있습니다.  

    setupFilesAfterEnv(string[]): jest가 구동 된 후, 실행되는 파일을 지정할 수 있습니다. test에 필요한 리소스들의 File path를 string 형태로 입력하면 됩니다.  

    testEnvironment: 기본적으로 jest로 구동하면 node 환경이기 때문에 dom rendering이 잘 안될 수 있습니다. 'jsdom'으로 value 값을 설정하면 JSdom이라는 라이브러리를 통해 컴포넌트들이 렌더링되어 브라우저 환경으로 인식할 수 있도록 세팅할 수 있습니다.  


test-utils.js 설정

이전단계까지 완료한 후에 react-testing-library의 문서를 보고 테스팅을 실시하면 됩니다. 하지만 문제가 있습니다. page 전체를 렌더링 할 때 사용하는 redux store가 주입이 되지 않아 컴포넌트에서 store에 접근할 수 없습니다. 따라서 테스트 환경에서 redux store에 접근이 가능하도록 세팅을 해주어야 합니다.


문서를 첨부하여 설명합니다.

https://testing-library.com/docs/react-testing-library/setup#custom-render

react-testing-library에서 제공하는 render함수를 커스텀하여 store를 주입한 형태의 새로운 render함수를 리턴합니다. 이를 이용하여 테스트 코드를 작성할 때 page를 렌더링 시키기만 하면 test-utils.js에서 설정한 store에 접근하여 read, write 모두 가능하게 됩니다.


이렇게 세팅을 하면 테스트 환경임에도 불구하고 브라우저에서 실행된 것처럼 모든 컴포넌트들을 작동시킬 수 있습니다.


Mock-Service-Worker 설정

한가지가 더 남았습니다. 서버와의 통신으로 받아오는 데이터는 테스트 환경에서 접근할 수 없습니다. fetch해오는 데이터를 미리 설정해 두어야 합니다. 이 작업은 msw라는 라이브러리의 도움을 받았습니다. 테스트환경에서 렌더링 된 상태에서 api 호출이 있으면 그 호출을 msw에서 가로채어서 mock data를 뿌려줄 수 있습니다.


설정 방법은 간단하기 때문에 문서를 첨부하여 대신합니다.

https://mswjs.io/docs/basics/request-handler



테스트를 돌려보자~

이제 샘플 테스트 코드를 돌려보겠습니다.

샘플로 JsonViewer라는 간단한 컴포넌트를 테스트해보았습니다. 테스트 내용은 다음과 같습니다.


JsonViewer를 렌더링하면 "닫기"버튼도 함께 렌더링 된다.
"닫기" 버튼을 클릭하면 JsonViewer가 화면에서 사라지기 때문에 "닫기" 버튼도 함께 사라진다.

user의 action은 fireEvent라는 API로 컨트롤 할 수 있습니다. 이때 리렌더링 과정은 비동기로 이루어지므로 그 이후의 검사는 waitFor의 callback 함수로 실행하여야 합니다.


모든 테스트가 잘 통과 되었습니다. 야호!



이렇게 간단하게 적었지만 테스트를 세팅하는 과정에서 정말 삽질을 많이 했습니다. 그만큼 많이 배운 것 같습니다. 테스트가 잘 통과되었을 때 정말 뿌듯하더라구요. 혹시 프로젝트를 하신다면 테스팅으로 생각하기 어려운 버그들을 검증해보시면 좋을 것 같습니다.

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari