테스트 코드를 작성할 때 한 번쯤 생각해보면 좋은 글
테스트 코드를 작성할 때 한 번쯤 생각해보면 좋은 글

테스트 코드를 작성할 때 한 번쯤 생각해보면 좋은 글

Tags
Test
Published
February 15, 2024
Author
lkdcode
테스트 코드도 유지 보수와 가독성을 신경 써야 한다. 많은 기능들을 하나의 메서드에 담고 있는 것을 금기시 하는 것과 같은 이유다. 테스트 코드를 작성할 때 어떤 기법들이 있는지 혹은 지켜야할 생활 체조(?)같은 것들이 있는지 지키면 좋은 것들, 혹은 알고 있으면 좋은 것들을 간략하게 알아본다.
 

🎯 given-when-then 패턴

테스트 코드도 유지 보수를 하고 가독성을 신경써야 한다. 일관성 있는 패턴을 유지하여 가독성을 향상 시킨다.
@Test void test() throws Exception { // given // when // then }
 

🎯 테스트 코드와 유지 보수

  1. 변수나 필드를 사용해서 기댓값 표현하지 않기
  1. 두 개 이상을 검증하지 않기
  1. 정확하게 일치하는 값으로 모의 객체 설정하지 않기
  1. 과도하게 구현 검증하지 않기
  1. 셋업을 이용해서 중복된 상황을 설정하지 않기
  1. 통합 테스트에서 데이터 공유 주의하기
  1. 통합 테스트의 상황 설정을 위한 보조 클래스 사용하기
  1. 실행 환경이 다르다고 실패하지 않기
  1. 실행 시점이 다르다고 실패하지 않기
  1. 랜덤하게 실패하지 않기
  1. 필요하지 않은 값은 설정하지 않기
  1. 단위 테스트를 위한 객체 생성 보조 클래스
  1. 조건부로 검증하지 않기
  1. 통합 테스트는 필요하지 않은 범위까지 연동하지 않기
 

🎯 변경에 유연하고 테스트하기 좋은 코드?

 

테스트할 수 없다면 public Class

  • ex. coreLogic1()coreLogic2() 의 메서드가 중요하다면 테스트를 위해 클래스 추출을 고려하자.
class AClazz { public void logic() { coreLogic1(); coreLogic2(); } private void coreLogic1() { ... } private void coreLogic2() { ... } }
 

테스트할 수 없다면 하드 코딩됐을 가능성이 높다

테스트가 불가능하거나 까다로운 코드는 제외한다.
  • try-catch
  • while : 무한 루프를 위한 테스트 코드는 작성하기가 어렵다.
  • randomeNumber() : 랜덤 숫자를 생성하는 테스트 코드는 작성하기가 어렵다.
 

🎯 Right-BICEP

  • Right: 결과가 올바른가?
  • B: 경계 조건은 맞는가?
  • I: 역 관계를 검사할 수 있는가?
  • C: 다른 수단을 활용하여 교차 검사할 수 있는가?
  • E: 오류 조건을 강제로 일어나게 할 수 있는가?
  • P: 성능 조건은 기준에 부합하는가?
 

[Right]-BICEP: 결과가 올바른가?

  1. '코드가 정상적으로 작동한다면, 그것을 알 수 있을까?'
  1. 다른 관점으로, 작은 부분의 코드에 대해 행복 경로 테스트를 할 수 없다면 그 내용을 완전히 이해하지 못한 것이다.
  1. 모든 질문에 대답할 수 없다면 그 최선의 판단으로 테스트를 작성하라.
 

Right-[B]ICEP: 경계 조건은 맞는가?

  • 모호하고 일관성 없는 입력 값. (ex. 특수 문자("!*W:X&Gi/w$->>$g/h#WQ@))가 포함된 파일이름
  • 잘못된 양식의 데이터. (ex. fred@foobar.)
  • 수치적 오버플로우를 일으키는 계산
  • 비거나 빠진 값. (ex. 0, 0.0, "", null)
  • 이성적인 기댓값을 훨씬 벗어나는 값. (ex. 150세의 나이)
  • 중복을 허용해서는 안 되는 목록에 중복 값이 있는 경우
 

경계 조건에서는 CORRECT를 기억하라

  • [C]conformance(준수): 값이 기대한 양식을 준수하고 있는가?
  • [O]rdering(순서): 값의 집합이 적절하게 정렬되거나 정렬되지 않았나?
  • [R]ange(범위): 이성적인 최솟값과 최댓값 안에 있는가?
  • [R]eference(참조): 코드 자체에서 통제할 수 없는 어떤 외부 참조를 포함하고 있는가?
  • [E]xistence(존재): 값이 존재하는가?(non-null, non-zero, 집합에 존재하는가? 등)
  • [C]ardinality(기수): 정확히 충분한 값들이 있는가?
  • [T]ime(절대적 혹은 상대적 시간): 모든 것이 순서대로 일어나는가? 정확한 시간에? 정시에?
 

Right-B[I]CEP: 역 관계를 검사할 수 있는가?

수학에서 덧셈의 검증으로 뺄셈을 사용하고, 나눗셈의 검증을 곱셈을 사용하는 것처럼
교차 검사를 통해 전체를 찾는다.
ex. 긍정 사례 답변들 + 역 사례 답변들 = 전체
 

Right-BI[C]EP: 다른 수단을 활용하여 교차 검사할 수 있는가?

ex. 제곱근을 제공해주는 자바 라이브러리 사용해 내가 만든 제곱근 메서드와 같은지 비교해본다.
ex. 대출된 도서와 대출되지 않은 도서의 합은 도서의 총 수량과 같아야 한다.
클래스의 서로 다른 조각 데이터를 사용하여 모든 데이터가 합산되는지 확인해보는 것.
 

Right-BIC[E]P: 오류 조건을 강제로 일어나게 할 수 있는가?

  • 메모리가 가득 찰 때
  • 디스크 공간이 가득 찰 때
  • 클라이언트 시간과 서버 시간이 다를 때 (벽시계 시간에 관한 문제들)
  • 네트워크 가용성 및 오류들
  • 시스템 로드
  • 제한된 색상 팔레트
  • 매우 높거나 낮은 비디오 해상도
로직 전체에 대한 커버리지를 달성하는 것이 아닌 예상하지 못 한 조건도 핸들링 해야 한다.
 

Right-BICE[P]: 성능 조건은 기준에 부합하는가?

추축만으로 성능 문제에 대응하기 보단 단위 테스트의 결과로 대응하라. 모든 성능 최적화 시도는 실제 데이터로 해야 하며 추측을 기반으로 해서는 안 된다. 성능이 핵심 고려 사항이라면 단위 테스트보다는 좀 더 고수준에서 문제에 집중하고 싶을 것이고, JMeter 같은 도구를 사용하길 원할 수도 있다.
 
JUnitPerf: 단위 수준 성능 측정 서드 파티 도구
 

🎯 FIRST: 좋은 테스트 조건

  • Fast: 빠른
  • Isolated: 고립된
  • Repeatable: 반복 가능한
  • Self-validating: 스스로 검증 가능한
  • Timely: 적시의
 

Fast

  1. 테스트를 빠르게 유지하라.
  1. 단위 테스트가 느리다면 무언가 잘못된 방향으로 나아가고 있는 것이다.
  1. 설계를 깨끗하게 하면 빠르게 유지가 가능하다.
  1. 더 자주 merge하여 변경 사항이 나머지 시스템에 어떤 영향을 주는지 파악하라.

Isolated

  1. 좋은 단위 테스트는 다른 단위 테스트에 의존하지 않는다.
  1. 단위 테스트를 독립적으로 유지하라.
  1. 테스트 메서드가 하나 이상의 이유로 깨진다면 테스트를 분할하는 것을 고려하라.

Repeatable

  1. 실행할 때마다 결과가 같아야 한다.
  1. 통제할 수 없는 요소를 격리하고 독립성을 유지하라.
  1. 각 테스트는 항상 동일한 결과를 만들어 내야 합니다.

Self-validating

  1. 테스트는 기대하는 것이 무엇인지 단언해야한다.
  1. 테스트는 스스로 검증할 뿐만 아니라 준비할 수도 있어야 한다.

Timely

  1. 적합한 시간에 테스트 코드를 작성해야 한다.
  1. 팀 규칙을 세우는 것도 좋은 방법이다.