3 minute read

프로덕트를 구현할 때 자동화 테스트를 개발 프로세스에 도입해야 한다는 말을 자주듣는다. 나의 클라이언트 개발에 테스트를 도입하는것은 쉽고 완만한 여정만은 아닌것같다.

테스트 주도 개발?

재작년 이맘때 쯔음 작은 어드민 대시보드 성격의 프로덕트를 개발한 적이 있는데 일정 내에 충분히 감당할 수 있겠다고 여겨지는 적당한 규모의 프로젝트 였다. 때문에 나는 그간 들어왔던 TDD 를 개발 중 시도해보았다. Jest 와 React Testing Library 를 이용하여 만들고자하는 함수와 컴포넌트 기능 하나하나마다 테스트를 작성하였다.

첫번째로 mocking 개념을 이해하는게 여간 어려운게 아니었다. 테스트를 작성할때에 벡엔드 API 의 응답을 모방하고 외부 라이브러리 훅들을 모방해야 했는데 이 부분을 작성하는데에 시간이 많이 소요되었다.

둘째로 구체적으로 어떠한 테스트를 작성해야하는지가 잘 연상되지 않았다.
데이터가 주입하면 리스트가 렌더링 되는 컴포넌트가 있는데 한 화면에 몇개의 테스트를 보여주는지까지만 테스트해야되는지, 리스트 아이템들의 콘텐츠들을 mock 데이터와 하나하나 비교하는 식으로 테스트를 작성해야하는지, hover 동작에 따라 아이템이 강조되는 동작이 있을 경우 이러한 테스트는 어떻게 작성해야하는지, 작성하는게 맞는지 등 테스트를 작성하며 여러 모호한 고민이 꼬리에 꼬리를 물었다.

결국 떠오르는 테스트를 모두 작성했고, 2주 동안 이렇게 개발을 하며 커맨드를 입력하면 내가 작성한 테스트의 갯수와 green 이 뜨며 테스트가 통과하는걸 동료들에게 보여주며 뿌듯해 했다. 거기까지 였다. 이후 프로젝트가 진행되며 스팩이 크고 작게 변경됨에 따라 많은 테스트 케이스들이 유효하지 않게 되었다.
테스트를 수정해가며 변경에 대응했으면 좋았겠지만 이때 생산성 측면에서 발목을 크게 잡히는 느낌이였다. 결국 이 시점에서 테스트를 수정하지 않고 코드를 수정하여 기민하게 대응하는 것을 택했고, 어느정도 시간이 지난 이후 이따금 상한 테스트 코드들을 실행해보면 수십개의 테스트를 실패하는 모습을 보게되었다.

결론적으로 당시 내가 느낀 어려움은 다음과 같았다.

  1. 3 만큼의 시간이 있다면 테스트 작성을 하는데 2, 제품을 구현하는데에 1의 시간이 걸렸다. 숙련도 부족으로 테스트에 대한 자신감이 저하되었다.
  2. 내가 작성한 테스트 케이스들이 제품에 도움이 되는 테스트 케이스라는것을 확신할 수 없었다.
  3. 결과적으로 자신감보다는 테스트를 실행하는데에 또 어느 테스트가 망가졌을지 공포감을 느끼게 되었고 테스트를 개발 프로세스에서 배재했다.

당시를 회고해보면 나는 테스트 자체가 가져다주는 실용주의적 측면보다는, TDD 라는 트랜디한 키워드 자체에 매료되었던것 같다.

당시를 떠올려보면 적절한 타협안을 찾았더라면 좋았겠다 싶다. 테스트 커버리지의 욕심, TDD 의 프로세스에 매몰되기보다는 ‘자동화 테스트를 통해 결과물에 대한 자신감을 얻자’ 는 측면에 집중하며 시도해볼만하다 싶은 부분에는 TDD 를 적용해보고, 숙련도가 부족하다면 구현을 먼저하고 단위 테스트를 작성해보는 식으로 욕심을 덜어냈더라면 결과가 달라졌을 것이다.

e2e 테스트와 Cypress

현재는 cypress 라는 도구로 e2e 테스트 를 작성하는 방법을 동료들과 스터디하고 있는데 나는 이 도구가 썩 마음에 든다. “특정 이벤트가 발생되면 사용자 브라우저에 콘텐츠가 노출되는지” 등을 모킹에 대한 걱정없이 스무스하게 작성할 수 있었고 이러한 테스트를 검증하는 과정을 브라우저를 통해 실시간으로 확인할 수 있단 점이 시각적으로 나에게 매우 큰 즐거움을 준다.

무엇보다 즐거운 점은 QA 엔지니어들과 공감대를 형성할 수 있고 QA 엔지니어들과 함께 테스트를 작성할 수도 있겠다는 점이다. Cypress : Testing Types 란 아티클을 보면 다음과 같이 e2e테스트와 단위테스트의 장점을 비교해둔 테이블을 확인할 수 있다.

종류 E2E 테스트 단위 테스트
테스트 대상 앱의 구성 요소
특성 포괄적이고 느리다. 특정적이고 신속하다.
검증 주제 결합된 구성요소들의 작동을 검증 개별 구성 요소의 테스트
작성자 개발자, QA 팀, 테스트 엔지니어 개발자, 디자이너
CI Infrastructure 종종 복잡한 설명이 필요하곤 함 불필요

앱의 기능에 대한 검증이라는 테스트의 본질을 이점으로 가져가기 쉽다.

또하나의 재밌는 점으로 Cypress 는 jQuery 를 이용하여 DOM 에 엑세스 한다는 점이다. jQuery 는 검증하고자 하는 DOM 에 접근할때에 정말 편하게 접근할 수 있고 선택과 검증을 메소드 체이닝을 통해 표현 할 수 있다.

$.fn 으로 필요한 메소드를 커스텀하여 정의하듯이 Custom Commands 를 통해 필요한 메서드를 정의하여 재사용할 수 있다. 다분히 익숙하게 느껴지는 방식이다.

아래는 내가 cypress를 연습하며 작성한 다마고찌 앱의 청소 관련된 기능을 테스트하는 코드인데 테스트가 이러한 장점 덕에 쉽게 읽히게 작성할 수 있단 점이 너무 마음에 든다.

Cypress.Commands.add('cleanPoop', () => 
  cy
    .contains('Clean Poop')
    .click()
    .root()
)

it('Clean Poop 버튼을 누르면 Poop 이 지워진다.', () => {
  cy
    .cleanPoop()
    .hasPooped(false)
});

it('생성된 Poop 을 치울 때 마다 Clean Count 가 증가한다.', () => {
  cy
    .cleanPoop()
    .contains('Clean Count : 1');
});

결론

현재 나는 클라이언트 측의 로직상 중요한 계산을 하는 함수나, 리팩토링을 할때에 before & after 를 보장하기위해 간간히 단위테스트를 작성한다. 여전히 물흐르듯 단위 테스트를 작성하지는 못한다.

e2e 테스트도 즐겁게 학습을 하는 단계이지 무언가 가시적인 성과는 아직 거두지 못하였다.

조급함에 항상 주의하며 자동화 테스트를 나의 개발 프로세스에서 서서히 스며들게 해보고 싶다. 작은 시도들을 통해 경험치를 천천히 쌓아가며 그를 통해 자신감을 얻자.

Categories:

Updated: