Published on

프론트엔드 테스팅과 설계

Authors
  • avatar
    Name
    불타는 라쿤들
    Twitter

🦡 작성자 : 혜원

토스 개발자분이 진행한 "프론트엔드 테스팅과 설계" 강연을 듣고 와서
강의 내용 정리한 문서를 공유합니다 :)
테스트에 대한 좋은 내용이 담겨 있어서 백엔드에게도 추천...

좋은 엔지니어링

  • 비용 대비 창출해내는 가치의 크기를 극대화하는 것
  • 테스트 코드를 작성하는 데 드는 실비 대비 이득이 크도록

1. 테스트의 정의

범위에 따른 분류

  • 단위 테스트
  • 통합 테스트
  • 인수 테스트

기능에 따른 분류

  • 기능 테스트
    • 기능 : 제품의 요구사항
  • 비기능 테스트
    • 보안, 성능, 접근성

방식에 따른 분류

  • 명세 기반 테스트 (Black box test)
  • 구조 기반 테스트 (White box test)

크기에 따른 분류

  • 작은/중간/큰 테스트
  • 구글에서 이렇게 분류함
  • 단위/통합/인수랑 비슷함

개발자가 작성하는 테스트

  • 비용 대비 실익이 커야
  • 지속 가능해야

2. 테스트 해야 하는 이유

  1. 변화하는 코드에 대응하기
  2. Shift left : 오류가 검출될 수 있는 단계를 왼쪽으로 옮기자 (조기에 발견하자)
  3. 더 나은 설계와 코드
    • 설계
      • 코드를 사용하는 입장을 경험
      • 테스트를 작성하려고 할 때 비로소 보이는 것들
        • 확장 가능성
        • 인터페이스의 중요성
        • 코드, 모듈의 의도
    • 코드
      • 리팩토링이 가능한 코드
      • 필연적으로 코드 수정이 필요함
    • 웹 접근성
      • 제품 사용자의 입장이 되는 경험
      • 테스트를 하기 위한 접근성 고려
  4. 문서화와 커뮤니케이션
    • 문서로서의 테스트 코드

→ 이러한 이유를 충족시킬 수 있는 테스트 코드를 작성해야 한다!

3. 무엇을 테스트 할 것인가

기능과 구현

  • 기능 = 동작 = 책임
  • 구현 = 세부사항
  • 기능을 테스트 해야 하며, 구현이 드러나면 안 된다
  • ex) Counter
    • 기능 : 버튼을 누르면 숫자가 올라간다
    • 구현 : 숫자는 리액트의 state로 관리한다

4. 어떻게 테스트 할 것인가

테스트에 대한 오해

  1. 테스트의 목적은 버그의 박멸이다.
    • 테스트는 버그의 존재를 알려줄 뿐, 부재를 알려주진 않는다
    • 모든 버그를 잡기 위해 많은 비용을 들이지 말자
    • 대신 발견되는 버그를 재현하여 테스트 케이스로 관리한다
  2. 테스트를 작성할 때, 제품 코드에는 변경이 발생하면 안 된다.
    • 구현을 테스트 하기 위한 변경 ❌
    • 테스트 코드만을 위한 변경 ❌
      • Code pollution (코드 오염) : data-testid
      • 접근 제어자의 변경(private → public)
    • 기능을 테스트 하기 위한 설계 변경 ✅
  3. 테스트하기 좋은 코드가 좋은 코드다.
    • 테스트 코드를 잘 작성하려다 보면 설계가 수정됨
  4. 테스트 커버리지는 의미없다.
    • 코드 커버리지, 분기 커버리지
    • 동기부여, 단기적인 목표 면에서 유의미한 지표로 활용될 수 있다
  5. 테스트 코드는 없는 것보단 낫다
    • 잘못된 테스트 코드는 오히려 방해

테스트가 어려운 이유

  • 제품이 동작하는 환경 : 브라우저
  • 테스트가 동작하는 환경 : Node.js

→ 브라우저에는 있고 Node.js에는 없는 게 많다…

  • UI

    • 외부와의 상호작용
      • 사용자와
      • 브라우저와
      • 서버와
    • 상태
      • UI
      • client state
      • runtime state
      • server state
      • browser state
  • 프론트엔드 애플리케이션은 무언가에 의존하고 있기 때문에 테스트가 어렵다

의존성 관리 전략

  • 경계를 잘 나누자
    • 외부 의존성인가 → Dependency injection
      • Remote server
      • Browser storage
      • Browser object model
    • 인프라인가 → Mocking
      • Document object model
      • JavaScript
      • React
      • Router
  • Mocking
    • 단점
      • 테스트가 Fragile 하다
  • Dependency Injection
    • 장점
      • 구현이 드러나지 않는다
      • 변경에 내성이 강하다
      • Pure JavaScript Object로 표현된다
    • 단점
      • 제품 설계의 변경이 필요하다

전략

  • 의존성을 식별하고 어떻게 관리할지 정한다
  • 관리 전략에 따라 제품 코드를 수정하면서 테스트 코드 작성
  • 기능 위주로 테스트 작성
  • 식별된 버그를 테스트로 작성

5. 언제 테스트 할 것인가

  • 테스트 코드를 작성하는 비용 ↔ 테스트 코드로부터 오는 효용
  • Shift front
    • Shift left보다 더 당기자
    • 테스트에 용이한 설계를 하자
    • 제품이 안정 궤도에 오르게 됐을 때(시장 검증 완료), 테스트 작성

마무리

  • 테스트는 생각보다 중요하다

  • 소프트웨어는 변경이 기본이다

  • 테스트 해야 하는 이유에 입각한 좋은 테스트 코드 작성

  • 기능을 테스트하되 구현이 드러나지 않도록

  • 제품의 생명 주기에 따른 테스팅 전략 고민

  • 의존성 관리 전략에 기반한 테스트에 용이한 설계

테스트가 어려운 진짜 이유

  • 중요하게 생각하지 않아서

Action Item

무게 중심을 테스트 코드로 옮기자!

  1. 테스트 공부하기
  2. 테스트 작성해보기
    1. 기능에 집중하기
    2. 의존성 식별하기
  3. 꾸준히 작성해보기
    1. 깨지는 테스트 고쳐보기
    2. 설계 바꿔보기
  4. 설계 공부하기

질의응답

요구사항이 빈번하게 바뀔 수 있는 상황에서도 테스트 코드를 도입해야할 필요가 있을까요? 기껏 만들어놓았는데, 사용자 반응이 좋지 않아 사용되지 않는다거나 당장 개발이 급한상황에서도 테스트 코드 비중을 높게 두는게 좋을지 궁금합니다.

  • 테스트 코드의 비중을 높게 두지 않아도 될 것 같다

E2E 테스트

  • 개발자 입장에서는 비용 대비 실익이 크지 않다고 생각함

테스트 코드 관련하여 좋은 레퍼런스나 깃허브 레포가 있을까요?

  • 토스 slash 유닛 테스트 잘 작성되어 있다!
  • 프론트엔드 오픈소스가 많이 없다…

테스트를 점진적으로 도입할 수 있을까요?

  • Yes

테스트 문화를 도입하고 싶은데, 어떤 식으로 팀과 함께 시작해야할 지 조언해주실 수 있을까요?

  • 강연, 단위 테스트부터 스터디
  • PR에 테스트 코드 여부 포함

처음부터 설계를 잘 잡자는 말이 곧 의존성 주입을 고려해 코드를 짜야한다는 의미로 받아들이면 될까요?

  • 의존성 주입을 고려하면 자연스럽게 레이어가 생기고, 그 레이어를 토대로 설계

팀원들을 설득 시켜 도입하자 ! 라는 의견을 하나로 모아야 하는 험난한 과정이 있는데요, 이 과정에서 도입에 근거가 될 만한 데이터적 지표나 사례가 있나요 ?! 예를들면 테스트 코드 도입을 통해 frontend voc가 20% 줄어들었다 라던가요 !

  • 토스에서는 결제 성공률, 어느 정도의 주기로 장애가 발생하는지 등등의 지표가 잘 되어 있다.
  • 제품에 문제가 있다는 공감대가 먼저 형성이 되었다.

컴포넌트 테스트 코드에 대해서 중요하게 생각 하고 계신지도 궁금합니다!

  • 레이어를 잘 나눴다면 컴포넌트 단위에서 비즈니스 로직이 별로 없을 것
  • But, 컴포넌트에는 유저 액션이 연속적으로 발생하는 비즈니스 로직이 존재할 수도 있음
    • 이때는 작성
  • 중요하게 생각하고 있다 → 통합 테스트로 작성하려고 노력

저희회사는 hook 을 만들면 hook 에 대해서도 테스트코드를 만드는데요. 훅 검증을 할 때 어쩔 수 없이 구현이 포함되게 되는데 renderHook 으로 커스텀 훅을 테스팅하는 것은 어떻게 생각하시는지 궁금합니다!

  • 컴포넌트를 마운트 시켜서 거기서 hook을 테스트 → 이렇게 하면 구현이 드러나지 않게 됨