Web: React Testing Library의 개념과 간단한 예시

Heechan
HcleeDev
Published in
9 min readNov 26, 2021
Photo by Nguyen Dang Hoang Nhu on Unsplash

iOS 개발이 메인 업무이긴 하지만, Web 개발 업무도 조금조금씩 맡고 있다. 그러던 중 최근에 TDD와 테스팅에 대해서 공부를 하게 되었다. 공부를 했으니 실제로 테스트 코드도 짜보고 싶고, 기회가 되면 TDD도 시도해보고 싶지만 우리 프로젝트 사정상 iOS에는 아직 테스팅 환경이 마련되지 않은 상태였다.

그래서 일단 Web 업무 중 간단한 일을 맡았을 때 실제로 테스트 코드를 경험해보기로 했다.

이번주는 Web에서 테스팅을 적용하기 위해 배웠던 React Testing Library에 대해 알아보고, Mock에 대해 알아보자.

React Testing Library는 어떻게 돌아가는가

우리는 웹 개발을 할 때 React 프레임워크와 JavaScript, 혹은 TypeScript를 많이 사용한다. 아닌 경우도 많지만, 요즘 많은 사람들이 이 조합을 사용하고 있고 이 글도 이를 기준으로 작성할 것이다.

처음 테스트의 존재를 알게 된 프론트 개발자 입장에서는 이런 생각을 하지 않을까 싶다. 일단 나는 이렇게 생각했다.

“비즈니스 로직 테스트는 그렇다 치고… UI 테스트는 대체 어떻게 하는거지?

생각해보면 비즈니스 로직은 그냥 해당 로직이 요청하는 값을 주고, 우리가 기대하는 결과가 나오는지 정도만 체크해봐도 될 것만 같은데, UI 테스트는 그렇게 단순하게 흘러가는 느낌이 아니다.

일단 뭔가 클릭했을 때 어떤 변화가 일어나는지 눈으로 보고 확인해야 한다. 컴퓨터는 눈이 없을텐데 어떻게 확인하는지 의구심이 들고, 그거보다도 클릭은 당최 어떻게 하는지 감이 오지 않는다. 마우스 커서를 옮겨서 버튼을 눌러야 하는데, 대체 컴퓨터가 어떻게 ‘아 저게 그 버튼이구나!’하고 누른단 말인가.

하지만 라이브러리 이름에 React가 들어있는 것을 보니 뭔가 좋은 UI 테스트 방법을 가지고 있을 것 같은데, 과연 React Testing Library는 어떤 방식으로 동작하는 것일까?

우선 DOM에 대해 간단히 알아보도록 하자. DOM은 Document Object Model의 줄임말으로, 웹 페이지의 인터페이스를 표현하고 있는 문서의 구조라고 볼 수 있다.

https://ko.wikipedia.org/wiki/%EB%AC%B8%EC%84%9C_%EA%B0%9D%EC%B2%B4_%EB%AA%A8%EB%8D%B8#/media/%ED%8C%8C%EC%9D%BC:DOM-model.svg

우리가 바라보고 있는 각 웹 페이지들은 여러가지 요소, 객체들이 모여서 만든 문서라고 볼 수 있다. 위 이미지를 노드 트리라고 볼 수 있는데, 한 화면을 이루기 위한 여러가지 객체들의 내용과 구성, 그리고 객체 사이의 관계를 구조화한 정보를 DOM이 가지고 있다는 것을 알 수 있다.

브라우저는 HTML 문서와 JavaScript 소스를 받아와 그 정보를 바탕으로 DOM을 구성한다. 물론 DOM 그 자체로 화면에 보이는 것은 아니다. 우리가 열심히 만들어둔 CSS 관련 정보들과 DOM이 가지고 있는 노드 트리가 합쳐져야 흔히 볼 수 있는 웹 페이지의 형태가 된다.

이 DOM은 현재 화면에 보이는 요소에 대한 정보는 모두 담고 있고, HTML 문서에는 적혀있더라도 현재 display: none 이라거나 조건 상 랜더링이 되지 않는 경우에는 노드 트리에 포함하지 않는다.

여기서 알 수 있는 점은 이 DOM 방식을 잘 이용하면 컴퓨터도 노드 트리를 검토하면서 현재 화면에 보이는 요소를 전부 알 수 있을 것이란 점이다.

React Testing Library는 이 DOM을 활용해 우리가 UI를 직접 테스트할 수 있도록 해주는 라이브러리다. React Testing Library는 DOM Testing Library를 기반으로 만들어졌는데, 그 DOM Testing Library에 대해서 공식 문서에는 아래처럼 소개하고 있다.

JavaScript 테스트 프레임워크인 Jest에서 기본으로 사용하는 JSDOM을 이용해 DOM 노드 트리를 형성하고, 그 노드 트리 위에서 우리가 원하는 요소들을 찾아가며 테스트할 수 있도록 해준다.

여기서 JSDOM은 표준적인 DOM 구성 방식을 따른 순수 JavaScript DOM으로, 테스팅과 실제 웹 추출 등에 활용하기 위해 만들어진 도구라고 생각하면 된다.

위 이미지에도 적혀있지만, 이 방식을 이용해 테스트를 진행했을 때 우리는 실제로 우리가 유저에게 기대하는 웹 페이지를 이용하는 방식과 비슷하게 테스트할 수 있다. 유저가 이런 버튼을 누르면 웹 페이지에 어떤 변화가 보여지는지, 우리가 기대하는 기능이 제대로 작동하는지 실제 사용자 입장에서 테스트하고, 앱에 대한 신뢰도를 높일 수 있다.

React Testing Library는 위 DOM Testing Library를 React 컴포넌트를 테스트할 때 사용하기 좋게 만들었다고 볼 수 있겠다. 공식 문서를 보면 React 말고도 굉장히 다양한 Testing Library들이 있다.

실제 예제로 이해해보기

그러면 간단한 예제로 어떤 식으로 테스팅이 일어나는지 대충 알아보자.

매우 간단한 MainPage를 만들어보았다. 지금 이 웹페이지에는 정직하게 ‘버튼’이라고 적힌 버튼만 덩그러니 놓여져있을 것이다. 한번 확인해보면…

아직은 아무짝에도 쓸모없는 버튼이지만 우리는 이 버튼이 제대로 만들어져있는지 테스트로써 보장하고 싶을 수 있다.

만약 테스트를 사용하지 않고 일반적인 사람이 눈으로 직접 확인하고 싶다면 아래와 같이 하면 된다.

  • 웹 페이지를 랜더링한다.
  • 랜더링된 페이지에서 ‘버튼’이라고 적힌 버튼을 찾는다.
  • 아하! 우리의 기대의 충족하는군.

사실 테스트 코드도 위 과정과 똑같다.

  • 웹 페이지를 랜더링한다

render(<MainPage />) 로 MainPage를 DOM으로 랜더링한다.

  • 랜더링된 페이지에서 ‘버튼’이라고 적힌 버튼을 찾는다.

지금 랜더링된 화면, screen 에서 ‘버튼’이라는 Text가 적혀있는 컴포넌트를 가져와서, button 에 저장한다. getByText("버튼") 이 그 역할을 하고 있다. 이 메서드를 이용하면 DOM의 노드 트리를 훑으면서 ‘버튼’이라고 적힌 컴포넌트를 가져온다고 생각하면 된다. 저기에 console.log(button) 을 해보면 아래처럼 나온다. 굉장히 길긴 한데 일단 상단에서 HTMLButtonElement라는걸 확인할 수 있다.

getByText 말고도 굉장히 다양한 방식의 찾기를 제공한다. 이는 문서에서 확인할 수 있을 것이다.

  • 아하! 우리의 기대에 충족하는군.

expect(button).toBeInTheDocument() 는 보면 알겠지만, 우리가 기대한 컴포넌트가 이 문서 안에 존재하는지 판별하는 것이다. 여기서 toBeInTheDocument() 같은 메서드가 문제없이 통과되면, 이 "버튼이 보인다" 라는 테스트가 통과할 것이다.

한 번 yarn test , 혹은 npm test 를 눌러서 결과를 확인해보자.

통과되는 모습이다.

이 DOM에서 현재 화면에 보이는 모든 컴포넌트에 대한 정보를 가지고 있기 때문에, 컴퓨터도 우리가 코드로 제공해 준 약간의 정보만 있으면 컴포넌트를 찾아내 확인할 수 있다.

그러면 이번에 버튼을 눌렀을 때 어떤 변화가 일어난다면 어떨까?

간단하게 버튼을 누를 때마다 showLabel 이 토글하도록 해, “안녕하세요?” 라는 문구가 나타났다, 사라졌다를 반복할 것이다.

의도대로 일단 잘 작동하는 모습이다.

그러면 이것도 한번 테스트 코드로 어떻게 테스트해야 할지 알아보자.

일단 제대로 테스트하기 전에 이상하게 한 번 해보자. 버튼은 그냥 신경쓰지 않고 바로 “안녕하세요?”라는 문구가 문서 내에 있는지 확인하는 것이다. 왠지 React 컴포넌트로 존재하니 DOM에서 찾아오는 것 아닐까 불안해진다.

다행히 테스트가 나는 이런 Text 본 적 없다고 억울함을 호소하고 있다. 저기 보이는 HTML을 보면 버튼만 존재하는 것을 확인할 수 있는데, 이는 DOM에서는 현재 보이는 컴포넌트만 노드 트리에 담고 있다는 것을 볼 수 있는 부분이다.

그러면 이번엔 버튼을 한번 눌러봐주자.

fireEvent.click(button) 이 추가되었다. 확인해뒀던 버튼 컴포넌트를 fireEvent 를 이용해 눌러줬다. 클릭 이후에 화면 상에 “안녕하세요?”가 있는지 확인해보도록 했다.

잘 통과되는 모습이다.

위 예제를 통해 최소한의 React Testing Library의 동작 원리는 파악할 수 있었다. 랜더링 후 확인할 수 있는 DOM 위에서, 우리가 원하는 컴포넌트를 찾고, 상호작용하고, 우리의 기대를 확인하는 과정을 가볍게 확인해봤다.

결론

하지만 현실 세계에서의 테스팅은 위의 간단한 예제처럼 호락호락하지 않다. 비동기 처리라든가, Mocking이라든가, 같은 글자 컴포넌트가 여러 개 있을 때라거나, 우리가 알아봐야 할 것은 굉장히 많다.

지금도 열심히 공부하고 있긴 한데, 확실히 실제 프로젝트에 적용하다보니 꽤 어려운 점이 많은 것 같다. 차후에도 웹 테스팅에 대해서 더 써볼 수 있게 되면 또 작성해봐야겠다.

참고한 것

--

--

Heechan
HcleeDev

Junior iOS Developer / Front Web Developer, major in Computer Science