thumbnail
하루스터디에서 프론트엔드 테스팅 전략
Testing
2023.07.10.

우테코 level3를 시작하면서 팀 프로젝트를 진행하게 되었다. 우리 팀에 대해서는 여기서 확인할 수 있다!

프로젝트를 진행하며 개발에 들어가기 앞서 우리 팀(프론트엔드)은 테스트 진행을 어떻게 할지 논의했다.

여러 테스트 도구가 있지만, 우리는 storybook, jest 기반으로 react-testing-librarymsw를 사용하기로 했다.


이 글을 쓰는 이유는 다음과 같다.

  1. 왜 이 테스트 도구들을 선택했는지에 대해 정리하고 싶었다.

  2. 테스트 환경 설정을 하면서 따로 설정해야하는 부분이 있었는데, 그 부분들을 기록으로 남기고 싶었다.

이 순서대로 글을 써보겠다.

테스트 도구 선택 과정

먼저 도구를 정하기 전에 논의한 것이 있다. 우리는 무엇을 테스트 할지(테스트 대상), 어떻게 테스트를 할지, 그리고 언제 어디서 테스트할지에 대해 논의했다. 테스트 코드 또한 리소스이기 때문에 스프린트 단위로 프로젝트를 진행하는 우리 팀은 테스트 커버리지를 높혀 전 범위를 테스트하면 좋겠지만 시간적인 여유가 많이 없기 때문에 테스트 우선순위를 정해야만 했다. 어떤 범위까지 테스트할지를 정해야 우리 팀 테스트 전략에 적합한 도구를 고를 수 있다고 판단했다. 현재 나와 있는 테스트 툴들이 관심사가 각기 다르다. 예를들어 jest는 단위 테스트에 조금 더 적합하고, Cypress는 E2E 테스트에 좀 더 친화적이고 등 각자의 관심사가 다르기 때문에 이런 논의를 먼저 진행했다.


그래서 우리는 무엇을 테스트 할지 이야기했고, 첫 번째 테스트 대상은 유저가 원하는 것을 테스트 하기로 결정했다. 즉, 유저의 행위를 중점적으로 테스트 하기로 한 것이다. 테스트 코드를 작성하는 이유는 서비스의 안정성을 평가하기 위함이기 때문에 우리 서비스가 제공하는 기능에 대해 제대로 동작하는지에 대한 테스트가 가장 중요하다고 생각을 했다. 예를 들어 유저가 하루스터디 Header에 있는 내 스터디란 버튼을 클릭했을 때 내 스터디에 관련된 내용이 뜨게 하는 기능 자체를 테스트하는 것이 중요한 것이지 유저가 관심 없는 부분 즉, 이 버튼을 눌렀을 때 상태가 어떻게 되는지나 버튼이 button 태그로 만들어 졌는지에 대해서는 빠르게 프로덕트를 출시해야하는 입장에서 당장 우선순위가 높지 않다고 판단했다.


유저의 행위를 중점적으로 테스트하려면 단일 컴포넌트를 테스트하는 것이 아닌 여러 컴포넌트들이 묶여 서로 상호작용하는 것을 테스트하게 될 것이므로 우리는 페이지 단위의 통합테스트(Integration Test)를 하기로 했다. 하나의 페이지에서 유저가 할 수 있는 행동을 기준으로 테스트를 작성하면 실제로 내부 구현이 바뀌고, 데이터를 다루는 방식이 바뀌더라도 테스트 코드의 변경 없이 유저에게 일관된 기능 제공을 보장할 수 있기 때문이다.


사용자 이벤트 처리 중심으로 테스트가 이뤄질테고, 이에 가장 적합한 테스트 도구인 Jest 기반의 React-testing-library를 사용하기로 결정했다. React-testing-library는 사용자 관점에서 애플리케이션 테스트하는 것을 강조하고 있고, DOM에 대한 접근을 getByText, getByTestId와 같은 메서드로 쉽게 DOM에 접근하여 테스트 코드를 작성할 수 있다는 장점이 있기에 우리 프로젝트에 적합한 테스트 도구라 생각했다.


기능 중에 어떤 버튼을 클릭하면 데이터를 받아와서 화면에 렌더링 시키는 경우가 있을 것이다. 이 경우엔 API와 통신하는 로직을 테스트해야 해야한다. React-testing-library를 사용하면서 jest를 사용하기 때문에 jest를 이용하여 fetch를 간단하게 모킹하여 테스트 코드를 작성할 수 있지만 Kent C. DoddsStop mocking fetch란 글을 보고 우리는 msw를 사용하기로 결정했다. 우리가 생각할 때 Kent C가 말하는 것 중 가장 와 닿은것은 msw가 응답을 mocking하고 설정하기 위한 작업이 fetch mocking하는 것보다 훨씬 간단하고, 실제 서버 응답과 일치시키는 작업도 편리하다는 것이었다. 즉, 테스트 코드에 대한 리소스가 확실히 줄어든다는 것이다. 또, msw를 도입하여 API 통신 로직 테스트가 가능하다면 유저의 행위를 테스트할 때 E2E 테스트까지 가능하기 때문에 추후 테스트 커버리지를 넓힐 경우에도 유용하다고 생각했다.


마지막으로 UI 테스트는 어떻게 하는 것이 좋을지 이야기했는데 이 또한 마찬가지로 jest를 이용하여 할 수 있었지만, 시각적으로 UI를 직접 볼 수 있고, 컴포넌트 단위로 스토리를 작성하여 UI 테스트 및 공유할 수 있는 StoryBook을 사용하기로 했다. 지금 프론트엔드 3명과 백엔드 4명이서 협업하고 있다. 개발만 하는 것이 아닌 기획도 같이하고 있기 때문에 이런 상황에서 기획한 디자인에 따라 개발한 컴포넌트를 스토리별로 문서화하고 백엔드 팀원들에게 직관적으로 보여줄 수 있다는 장점 또한 있어서 우리는 StoryBook을 사용하기로 했다.


이렇게 우리는 무엇을 테스트 하고, 어떻게 테스트 할지 정했다. 남은 것은 언제 어디서 테스트를 할지인데, 이 부분은 아직 명확히 정해진 것이 없다. 이번에 CI/CD를 구축하면서 CI 파이프라인에서 PR 생성 시 테스트 진행을 해서 테스트 실패 시 PR을 생성하지 않도록 하고 만약 테스트 성공하여 PR 생성이 된다면 merge 후 CD 파이프라인에서 테스트를 한번 더 진행하는 방식으로 하면 어떨까 생각만 하고 있는 중이다. 이 부분에 대해서는 추후에 정리할 예정이다.


이 외에도 테스트할 범위들은 더 많을 것이다. 성능 테스트라던지 접근성 테스트, 그리고 브라우저 호환성 테스트 등 많은 영역에서 테스트를 할 수 있을 것이다. 일단 개발에 들어가기 전에는 이 정도만 수립하고 들어가도 괜찮다고 생각했다. 사실 위에 서술한 테스트들은 해본 적이 없기도 하다. 나중에 프로젝트를 진행하면서 추가하게 된다면 정리해 볼 예정이다.

testing-library 설정 tip

CRA가 아닌 웹팩 기반으로 React 어플리케이션 환경을 설정했다. 그러다 보니 testing-library를 도입할 때 추가적으로 해줘야 하는 설정들이 있었다. 그 부분에 대해 간단하게 기록하려 한다.

react-testing-libary 및 jest-dom 설치

npm i -D @testing-library/react @testing-library/jest-dom

cf) jest-dom을 깔면 dom에 관련된 테스팅 메서드들을 제공한다.

jest 관련

npm i -D jest jest-environment-jsdom @types/jest

cf) jest에서 dom을 사용하기 위해 jest-environment-jsdom이 필요하다.

babel 관련

npm i -D @babel/preset-react @babel/plugin-transform-modules-commonjs @babel/plugin-transform-runtime

babel.config.js 설정

module.exports = {
  presets: [['@babel/preset-react', { runtime: 'automatic' }]],
  env: {
    test: {
      plugins: [
        '@babel/plugin-transform-modules-commonjs',
        '@babel/plugin-transform-runtime',
      ],
    },
  },
};

jest.config.js 설정

module.exports = { testEnvironment: 'jsdom' };

Reference

+ 내용 추가

반갑습니다. 누군가에겐 도움이 되는 글을 쓰도록 노력하겠습니다.
© October.2022 yeopto, Powered By Gatsby.