Frontend Testing Study | Test Introduction

오형근·2023년 1월 11일
0

Testing

목록 보기
2/5
post-thumbnail

테스트 코드를 작성하고 테스트를 진행하는 것은 서비스의 비즈니스 로직이 정확하게 의도한 대로 작동하는지 확인하고, 이것이 최종적으로 유저에게 전달될 때 언제나 동일한 서비스를 제공해줄 수 있는 코드인지 확인하기 위하여 진행하는 작업이다.

또한 기존에 사용하던 레거시 코드를 버리고 새로운 언어, 프레임워크를 도입하려고 하거나 부분적인 리팩토링을 진행하게 되면 기존의 로직이 어떤 인자를 받아서 어떤 값을 반환하였는지, 이러한 이펙트들이 연계되어 유저에게 무엇을 제공해주었는지를 정확히 기록해둘 필요가 있다. 이로 인해 테스트 코드 작성의 중요성을 시간이 갈수록 커져가고 있다.

기존의 테스트 코드 작성은 주로 백엔드 단에서 이루어지고는 했다. 백엔드에서 일어나는 다양한 DB연동, 트랜잭션, 타 API 요청, 그 외에 수많은 함수들이 정확히 의도된 대로 작동하는지 확인하는 일은 기술 부채의 감소와 서비스 품질 향상을 위해 필수적인 일이다. 그러나 프론트엔드에서는 이렇다 할 테스트 코드의 작성이 필수적으로 이루어지지는 않고 있던 것 같다.

그렇다면 그 이유가 무엇일까? 이는 최근 프론트엔드 단의 규모 증가와 세분화를 생각하면 답을 알 수 있다. SPA 등장을 기점으로 프론트엔드 분야는 기존에 html 템플릿 엔진(JSP 등...)으로 작성하여 백엔드에서 보내는 단적인 페이지만을 띄우는 SSG를 벗어나서 다양한 고민을 하는 전문 분야로 발전했다. 이에 따라 기존처럼 단순하게 함수가 받는 인자를 확인하고 반환값을 확인하여 함수의 로직이 잘 작동하는지 확인하는 테스팅은 이러한 프론트엔드에서는 좋은 테스팅이 아니게 되었다. 그도 그럴 것이 UI를 보는 유저는 함수의 인자가 잘 들어가고 반환값이 잘 나오는 것에는 신경을 쓰지 않을 테니까. 프론트엔드에서 중심적으로 테스팅해야하는 것은 렌더링된 화면이었다.

렌더링된 화면이 의도한 대로 잘 띄워지고 있는지 확인하기 위해서는 테스팅 도구나 방법 등에서의 변화가 필요했다.


프론트엔드 테스트

백엔드에서는 함수에 들어가는 파라미터, 그리고 로직을 통해 나온 반환값, 이 두 가지를 체크하는 것이 중심이 되었다. 그래서 기존의 백엔드 테스트 코드들을 보면 파라미터와 반환값을 중점적으로 체크하는 것을 볼 수 있다.

그렇다면 프론트엔드에서 파라미터와 반환값 역할을 하는 것은 무엇일까?

프론트엔드에서 변화를 가져오는 것은 UI 단에서의 이벤트(클릭, 입력 등)이고, 이로 인해 변화하는 것은 렌더링 되는 UI 그 자체라고 볼 수 있을 것이다. 따라서 우리는 사용자에 의해 발생한 이벤트에 주목하고 이로 인해 발생한 효과를 살펴보아야 한다.

이벤트 => UI 렌더링

로직을 통해 우리가 의도한 대로 렌더링이 되는지 확인하기 위해서는 새로운 테스팅 라이브러리가 필요했다. 그리고 이를 위하여 개발된 라이브러리 중 가장 유명한 것은 역시 react-testing-library인데, 이는 다른 글에서 제대로 다뤄보고자 한다. 단순하게 함수의 반환값을 판단하는 것에서 반환값이 DOM Element형태인 테스팅 라이브러리라고 생각하면 된다!

물론 이러한 테스트 라이브러리를 이용하면 스타일적인 요소들은 확인하기가 어렵다. 확인할 수 있는 것은 버튼이 DOM에 그려졌는가?, 버튼 클릭 이벤트가 발생했는가?, 특정 이벤트 발생 횟수가 얼마인가? 등등이다. 만일 스타일적인 요소를 확인하고 싶다면 Storybook라이브러리를 이용하면 좋을 것 같다. Storybook + Chromatic 을 이용하면 코드 변화 시 스타일 적인 요소가 어느 비율로 어떻게 변화하였는지 쉽게 확인할 수 있다.

소프트웨어 테스트 패턴

테스트 코드에도 여러 사람들에 의해 검증되고 상용화된 다양한 패턴들이 존재한다.

Given-When-Then

지금도 많이 사용되고 있는 given-when-then 패턴은 대표적인 테스트 패턴이며, Behaviour driven development(BDD)에 충실한 패턴이다. 각 단계를 풀어서 생각하면 '준비-실행-검증'라고 해석할 수 있다. 한 마디로 테스트 코드를 작성할 때 준비 / 실행 / 검증을 담당하는 코드를 나누어 작성해두면 된다는 것이다.

1. given

  • 테스트하고자 하는 행동을 시작하기 전에 그 상태를 미리 설명하여 조성해두는 부분이다.

2. when

  • when은 실제로 액션을 테스트하는 과정이다.

3. then

  • 마지막은 테스트를 검증하는 과정이다. 예상한 값, 실제 실행을 통해 나온 값을 검증한다.

아래 예제를 살펴보자. 출처

기능: 사용자 주식 트레이드

시나리오: 트레이드가 마감되기 전에 사용자가 판매를 요청

"Given" 나는 MSFT 주식을 100가지고 있다.
		그리고 나는 APPL 주식을 150 가지고 있다.
        그리고 시간은 트레이드가 종료되기 전이다.
        
'When"  나는 MSFT 주식을 20 팔도록 요청했다.

"Then"  나는 MSFT 주식을 80 가지고 있어야 한다.

그리고 나는 APPL 주식 150을 가지고 있어야 한다.
그리고 MSFT 주식 20 판매 요청이 실행되었어야 한다.

이러한 절차를 통해 테스트의 전체적인 구성과 목적, 흐름 등을 빠르게 파악하고 테스트의 성공 여부를 쉽게 판단할 수 있게 된다.

Describe-context-It

이 패턴은 코드의 행동을 설명하는 테스트 코드를 작성한다.
앞서 설명한 Given-When-Then패턴과 비슷한 철학을 가지고 있지만 미묘한 차이를 보이는 패턴이다.

이 패턴은 상황을 설명하기보다는 테스트 대상을 주인공 삼아서 행동을 더 섬세하게 설명하는데 적합하다.

각 단어는 다음을 나타낸다.

1. Describe

  • 설명할 테스트 대상을 명시한다.
  • 테스트 대상이 되는 클래스, 메서드 이름을 명시한다.

2. Context

  • 테스트 대상이 놓인 상황을 설명한다.
  • 테스트할 메서드에 입력할 파라미터를 설명한다.

3. It

  • 테스트 대상의 행동을 설명한다.
  • 테스트 대상 메서드가 무엇을 반환하는지 설명한다.
  • 여기서 영어로 Context문을 작성할 때에는 반드시 with 도는 when으로 시작하도록 한다.
  • It 구문은 "It returns true", "It responses 404"와 같이 심플하게 설명할수록 좋다.

이 방식은 다음과 같은 장점이 있다.

  • 테스트 코드를 계층 구조로 만들어준다.

  • 테스트 코드를 추가하거나 읽을 때 스코프 범위만 신경쓰면 된다.

  • "빠뜨린' 테스트 코드를 찾기 쉽다.
    -> 높은 테스트 커버리지가 필요할 때 도움이 된다.

안타깝게도 JS에서 널리 쓰이는 jest는 내장 기능응로 context를 제공해주지 않기 때문에, 우리는 jest-plugin-context라이브러리를 별도로 설치해야 한다.

그렇게 하여 작성된 계층 구조가 뚜렷한 테스트 코드는 다음과 같은 모습이다.

describe("sum", () => {
	context("with 300 and 200", () => {
    	it("returns 500", () => {
        	expect(sum(300, 200)).toBe(500)
        })
    })
  	
  	context("with -300 and 200", () => {
		it("returns -100", () => {
        	expect(sum(-300, 200)).toBe(-100)
        })
    })
})

이렇게 작성된 테스트 코드는 계층 구조로 나누어 살펴볼 수 있고, 해석이 매우 쉬워진다는 것을 알 수 있다.


지금까지 테스트 코드의 대표적인 패턴 두 가지에 대하여 알아보았다. 테스트 코드를 작성함에 있어서 패턴을 적용하는 것은 가독성을 높이고 이는 곧 유지보수를 원활하게 하는데에 도움을 준다는 것을 잊지 말자!

0개의 댓글