[The RED : 프론트엔드 Back to the Basics] 7. 테스트

posinity·2023년 6월 22일

당신이 만든 프로그램의 사용자는 두 부류다.
13살에 이미 국방부와 CIA를 해킹한 천재 해커와 버튼이 어디있는지 못 찾는 바보

극단적인 상황을 가정해야 하며, 방어적인 프로그래밍을 해야 한다!

테스트 예시

예를 들어 두 숫자를 더해주는 간단한 함수가 있다고 하자. 처음 테스트는 아마 다음과 같이 할 것이다.

expect(add(1, 6)).toBe(7);

그런데 함수는 정수만 다룬다고 정의해두었다고 생각해보자. 그러면 일부러 소숫점이 있는 값을 넣어본다.

expect(add(1.2, 6)).toBe(7);

소숫점을 정수로 변환하기는 했는데 반올림을 해야할까, 아니면 버림을 해야할까? 함수의 정의에 따라 이 부분도 테스트해야 한다.

expect(add(1.5, 6)).toBe(8);

일부러 반올림이 되는 끝자락에 있는 1.5와 같은 값을 넣어서 테스트 해본다.
숫자를 다루는 값인데 숫자가 아닌 값을 넣으면 어떻게 될까. 자바스크립트에서 정수가 표현할 수 있는 최고 숫자 혹은 최소 숫자를 넣으면 결과가 어떻게 변할까? 이런 식으로 극한의 값을 테스트하여 엣지 케이스를 방지할 수 있다.

좋은 테스트의 조건

  1. 실행 속도가 빨라야 함.
  2. 내부 구현(테스트하지 않는 부분)을 변경했다고 해서 깨지면 안됨. 인터페이스(입출력 위주)를 중심으로 작성. 비공개 메스드도 테스트를 해야하는가라는 논쟁을 가끔 볼 수 있는데 테스트의 목적이 모든 코드를 테스트하자는 게 아니라 공용 인터페이스가 작동하도록 보장하는 데 있음을 명심.
  3. 버그를 찾을 수 있어야 한다. 만들었다고 끝이 아님 테스트 시나리오를 잘 설정해야 함.
  4. 테스트 결과에 일관성이 있어야 함. 코드는 안 변했는데 실행할 때마다 테스트 결과가 달라지면 어쩔 거임. 그런데 그런 일도 생기긴 함. 우리 회사 CI의 E2E 테스트 (end to end 테스트)
  5. 의도가 명확히 드러나야 함.

테스트 커버리지

보통 라인 수 기준으로 측정. 70%만 넘어도 훌륭한 수준.
100%는 불가능. 억지로 100%로 맞추려고 어거지 코드를 작성하거나 중요한 로직이 없는 단순한 코드까지도 모두 테스트하는 건 오히려 시간 낭비.
특히 프론트엔드 개발에서는 사용자의 입력 등으로 해결해야 하는 부분이 많아 더 어려운 면이 있음.
E2E 테스트로 보완이 가능하긴 한데 완벽하게 된다는 뜻은 아님.
일단 브라우저 구동하고 사용자의 행동을 에뮬레이션하는 게 느림. 파일 드래그처럼 구현이 어려운 동작도 있음.

TDD, BDD

TDD : 테스트 주도 개발 방법론

장점

  1. 테스트를 먼저 작성하기 때문에 전체 코드에서 얼마나 많은 코드가 테스트되는가를 측정하는 테스트 커버리지 비율이 자연스럽게 높아진다.
  2. 테스트 되는 것만 코드로 작성하므로 코드가 방대해지지 않는다.
  3. 버그때문에 발생하는 시간 낭비 줄여주고, 코드가 원하는 바를 명확히 달성하는지 쉽게 확인

방법

  1. 테스트를 먼저 작성한다. 만족하는 코드가 없는 상태이므로 당연히 테스트는 실패함.
  2. 테스트를 통과하는 코드를 작성한다.
  3. 리팩터링: 중복이 보이거나 더 개선할 방법이 있다면 코드를 개선한다.

TDD의 3대 원칙 - 로버트 C. 마틴 (밥 아저씨, 클린 코더)

  1. 실패할 테스트를 작성하기 전에는 아무런 프로덕션 코드도 작성하지 않는다.
  2. 실패할 테스트 말고는 작성하지 않는다.
  3. 현재 실패한 테스트를 만족시키는 코드 외에는 작성하지 않는다.

ODA 원칙

맥스 카넷-알렉산더(구글의 Code Health 기술 책임자)는 저서 "심플 소프트웨어"에서 말한 TDD는 물론 모든 소프트웨어 개발에 적용될 수 있을만한 원칙
Observation, Descision, Action "결정하고 실행하기 전에 관찰부터 해라"

1주기 - 문제를 "관찰"하고, 해결할 지 어떨지 "결정"하고 테스트를 작성한다(실행).
2주기 - 테스트를 보고 API가 괜찮은지 관찰하고, 괜찮지 않으면 수정 방법을 결정하고, 테스트를 수정(실행). API가 괜찮아 보일 때까지 반복.
3주기 - API가 괜찮으면 테스트를 실행하고 통과하는 지 본다. 실패하겠지 (관찰), 테스트를 어떻게 통과할 지 방법을 정한다 코드 구현에 대한 설계 (결정), 코드를 작성한다. (실행)
4주기 - 테스트를 실행해서 작성한 코드가 테스트를 통과하는지 본다. (관찰), 통과하지 못하면 코드를 어떻게 수정할 지 결정한다. 코드를 작성한다 (실행) - 반복

TDD 실습

369게임 - 숫자 배열을 넣으면 369게임 규칙에 따라 숫자를 읽는 문자열을 반환하는 프로그램.
ex) game([1, 2, 3]) => '일,이,짝'

    1. [1, 2]만 넣어서 숫자를 읽는지 테스트 오류) 3/6/9에서는 짝
    1. 3이 들어가면 짝으로 나오는지 테스트. 오류) 두 자릿수라면 두 숫자 다 확인해야함
  • 33이 나오면 두 번 짝짝하는지 테스트. 최종적으로 세 자리도 테스트


적어도 제가 지금까지 일하면서 TDD를 제대로 진행하는 곳을 못 봤음.
처음엔 어느 정도 지켜지다가도 시간이 지나고 업무가 바쁘면 우선 순위가 밀리기도 함.

profile
문제를 해결하고 가치를 제공합니다

0개의 댓글