Frontend

리액트 테스팅 라이브러리(RTL)를 사용한 TDD 적용 도전기 1편 - 테스트 과정 중 만난 오류 (svg모듈 미인식 오류, theme 인식 오류)

코구리 2024. 3. 8. 17:20

1. TDD란?

TDD는 Test Driven Development (테스트주도 개발)의 약자로 구현 후에 테스트를 하는 것이 아니라 '실패하는' 테스트코드를 먼저 만들고 나서 그 테스트를 통과할 만큼 최소한의 구현을 하는 것을 말한다.

그로 인해 불필요한 코드가 생기지 않고 나의 코드에 대한 정확성을 보장할 수 있다.

우리 팀에서 10일간 만든 서비스를 디벨롭하기로 했는데 당시 TDD를 시도했다가 알수 없는 오류로 인해 포기했었다. 디벨롭하면서 추가되는 기능은 꼭 TDD로 개발해보고 싶은 마음이 들어서 바로 시작!

 

2. 테스트 도구 

나는  jest 를 사용했다. jest는 react create react app 으로 리액트 프로젝트를 설치하면 같이 설치된다. 그 이외에도 나는 타입스크립트를 사용했기 때문에 타입스크립트의 언어를 트랜스파일링 해주는 바벨을 설치하는 등 정말 많은 설정 끝에 타입스크립트에서의 테스트 환경을 구축할 수 있었다.

많은 시행착오가 있었는데 이 글에서는 환경을 구축하는 부분을 모두 다루기는 힘들고 내가 테스트하면서 환경설정 문제로 만났던 오류를 해결한 방법만 보여주려고 한다.

 

프론트 단에서는 UI에 대한 테스트와 기능 테스트(유닛 테스트)로 나눌 수 있다고 생각했다.

 

그럼 해당 UI를 만들기 위해서 어떻게 테스트할 수 있을까?

유저의 입장에서 생각해보면 어디에 어떤 태그가 잘 오는지가 중요한 게 아니라 데이터가 맞게 렌더링되는지가 중요한 관심사일 것이다. 예를 들면 로그인 버튼의 '로그인' 텍스트가 잘 나온다던지..

 

이런 니즈에 어울리는 라이브러리가 RTL(React Testing Library)이다. RTL은 jsdom이라는 라이브러리를 통해 실제 브라우저 DOM을 기준으로 테스트를 작성한다. 따라서 유저 입장에서 필요한 테스트를 하기 유용한 면이 있다. RTL도  react create react app로 설치하면 자동으로 설치되기 때문에 쉽게 사용이 가능하다.

 

3. 테스팅 과정과 테스팅 중 오류 해결

내가 만들려는 UI

 

내가 만들려는 UI의 최종 화면은 이렇다. 제일 먼저 헤더가 잘 렌더링 되는지 테스트해보려고 한다.

 

먼저 스타일 컴포넌트를 모아둘 style.ts, 컴포넌트의 비즈니스 로직 코드를 담을 Title.tsx , VAC역할(UI만)을 하는 TitleView.tsx 를 만들었다.

그리고 모두 기본 코드만 작성해둔 상태이다. 

 

헤더의 텍스트를 만들어줄 헤더 컴포넌트를 먼저 만들었다. 나는 텍스트가 나오는지 테스트하는 것이니까! 텍스트를 넣기 전에 테스트해주면 된다. 더 정확히 하려면 헤더 컴포넌트를 만들기 전에 테스트 하는 것이 더 좋을 것 같다.

Title.test.tsx에는 이렇게 헤더 텍스트가 잘 나오는지 테스트코드를 만들었다. 당연히 컴포넌트에 아무 텍스트를 넣지 않았기 때문에 이 테스트는 실패할 것이다.

 

1) 오류 1 - jest의 svg모듈 인식 오류

음? 그런데 텍스트가 없어서가 아니라 아예 코드를 읽지 못하는 것 같았다. 좀더 자세히 읽어보니 svg 이미지 파일을 모듈로 처리하지 못하는 문제가 있었다.

그래서 루트 경로에 svg파일을 변환해줄 수 있는 svgTransformer.js 를 만들어서 모듈로 정의해줬다. 

// svgTransformer.js

module.exports = {
	process() {
		return { code: 'module.exports = {};' };
	},
};

 

jest.config.js

해당 파일을 jest 설정파일인 jest.config.js 파일의  transform 옵션에 추가해줬다. 이렇게 되면  svg 파일을 컴파일링 할 때 저 변환기를 거치기 때문에 모듈로 인식할 것이다.

 

2) 오류 2- theme 인식 오류

 

그런데 이번에는 style에 정의한 테마를 jest가 읽지 못하는 문제가 있었다.

찾아보니 테마를 읽을 수 있도록 테스팅 라이브러리의 render 함수를 새롭게 정의해줘야 한다고 한다.

아마 최상위에서 theme로 감싸주고 있어서 하위에 속한 컴포넌트를 테스트했을 때 인식하지 못하는게 아닌가 싶다.

// customJestRender.js

import 'jest-styled-components'; //jest에서 스타일컴포넌트 사용을 위해 jest-styled-components 불러오기
import { ThemeProvider } from 'styled-components'; // 테마로 감싸주기 위한 themeProvider
import { render } from '@testing-library/react'; // 실제 testing 라이브러리의 render 함수 새롭게 정의 위해 불러오기
import { theme } from '../styles/theme.js'; // 정의해둔 theme.js 불러오기

const Wrapper = ({ children }) => <ThemeProvider theme={theme}>{children}</ThemeProvider>;

const renderWithStyledComponent = (ui, options) => render(ui, { wrapper: Wrapper, ...options });

export * from '@testing-library/react';

export { renderWithStyledComponent as render };

 

커스텀 함수를 담을 customJestRender.js 파일을 만들고 루트 디렉토리의 utils 폴더안에 넣어줬다.

원래 theme를 사용하려면 index.tsx 에서 App.tsx 컴포넌트를 ThemeProvider로 감싸줘야 한다. 그걸 재현하기 위해서 실제로 ThemeProvider 와 render를 불러온다.

 

그리고 자식 컴포넌트를 ThemeProvider 로 감싸는 Wrapper 컴포넌트를 만들어준다. 이 컴포넌트를 사용하여  render 함수를 renderWithStyledComponent 함수에 정의한다. 이제  renderWithStyledComponent 함수를 사용하면 ThemeProvider가 감싸진 컴포넌트가 렌더링 될것이다.

이 함수를 render 이름으로 export 해주면 테스트 파일에서 render로 불러올 수 있다.

 

이렇게 만들어준 파일을 jest.config.js 파일의 setupFilesAfterEnv 옵션에 넣어줬다.

// setupTest를 이용하여 환경 설정
setupFilesAfterEnv: ['<rootDir>/setupTest.js', '<rootDir>/src/utils/customJestRender.js'],

 

import { render } from '../../../utils/customJestRender'; //커스텀한 render 함수
import { fireEvent, screen } from '@testing-library/react'; //기존에 테스팅 라이브러리에서 불러오는 함수

 

그리고 이제부터는 이렇게 render 함수를 이 커스텀 함수 경로를 통해 불러와서 사용하면 된다. 원래는 render 역시 @testing-library/react에서 불러와서 사용했으나 지금은 render는 따로 불러오고 있다.

 

 

이렇게 하면 환경설정이 안돼서 나는 오류는 없다. 현재 텍스트를 넣어주지 않아서 실패를 의도한 테스트이다.

그럼 이제 테스트 통과를 위해 텍스트를 넣어보자!

 

늘 동일한 결과를 내기 위해 임의로 헤더에 들어갈 데이터를 만들어줬다.

원래는 api로 유저의 이름(name)과 칭호의 갯수(count)를 받아와 넘겨준다.

 

이렇게 만들어준 코드로 다시 성공하는 테스트를 해보기로 했다.

 

이렇게 잘 나온다. 이렇게 함으로써 확실히 로컬에서 눈으로 보지 않아도 코드에 대한 확신이 생기는듯 (벌써 김칫국ㅋㅋ)

근데 실행시간이 너무 오래걸리는 것 같아 개선할 수 있는 방안을 생각해야 할 것 같다.

 

암튼 이제 로컬 환경에서 확인해보자. 텍스트가 잘 나오는 것을 볼 수 있다. 이렇게 하면 TDD 방식으로 하나의 컴포넌트를 만든 것이다.

 

이렇게 만들었는데 '모은' 이후로 다음 줄로 넘어가게 하기 위해서 중간에 br 태그를 써줬다. 이런 부분까지 테스트하기는 힘들어서 바로 br태그를 추가해줬다.

 

하나의 컴포넌트를 TDD로 테스트하는 과정을 작성했는데 글이 길어져서 이후 전체 UI를 TDD로 만드는 과정은 다음 글에 작성하려고 한다!