Code

[단위 테스트] 6-1. 단위 테스트 스타일: 단위 테스트 스타일

noahkim_ 2025. 1. 25. 00:20

블라디미르 코리코프 님의 "단위 테스트" 책을 정리한 포스팅입니다.


1. 단위 테스트의 세 가지 스타일

출력 기반 테스트

  • 테스트 대상 시스템에 입력을 넣고, 생성되는 출력을 점검하는 방식
  • 부작용이 없으므로 반환 값만 검증하면 됨

 

함수형 프로그래밍
  • 부작용 없는 코드 선호를 강조하는 프로그래밍 방식

 

상태 기반 테스트

  • 작업이 완료된 후 시스템 상태를 확인하는 것
  • 의존성의 상태를 의미할 수 있음

 

통신 기반 테스트

  • 목을 사용해 테스트 대상 시스템과 협력자 간의 통신을 검증

 

2. 단위 테스트 스타일 비교

회귀 방지와 피드백 속도 지표로 스타일 비교하기

회귀 방지
  • 지표
    • 테스트 코드 양
    • 코드 복잡도
    • 도메인 유의성
  • 특정 스타일에 따라 달라지지 않음

 

테스트 피드백 속도
  • 테스트 스타일과 테스트 피드백 속도 사이에는 상관관계가 거의없음

 

리팩터링 내성 지표로 스타일 비교하기

  • 거짓양성 수에 대한 척도
  • 식별할 수 있는 동작이 아니라 코드의 구현 세부 사항에 결합된 테스트의 결과
  • 캡슐화를 잘 지키고 테스트를 식별할 수 있는 동작에만 결합하면 거짓 양성을 줄일 수 있음

 

출력 기반 테스트
@Test
void testAddNumbers() {
    int result = calculator.add(2, 3);
    assertEquals(5, result);
}

 

  • 테스트 대상 메서드에만 결합되므로 거짓 양성 방지에 가장 우수함

 

상태 기반 테스트
@Test
void testWithdrawMoney() {
    BankAccount account = new BankAccount(100);
    account.withdraw(50);
    
    // 내부 상태를 검증
    assertEquals(50, account.getBalance());
}

 

  • 거짓 양성이 많이 발생되기 쉬움
  • 테스트 대상 메서드 외에도 클래스 상태와 함께 작동함
  • 큰 API 노출 영역에 의존하므로, 구현 세부 사항과 결합할 가능성도 더 높음

 

통신 기반 테스트
@Test
void testSendNotification() {
    NotificationService mockService = mock(NotificationService.class);
    Order order = new Order(1, "item1");
    
    order.process(mockService);
    
    // Mock과의 상호작용 검증
    verify(mockService).send("Order 1 processed");
}
  • 가장 거짓 양성이 많이 발생되기 쉬움
  • 테스트 대역으로 상호 작용을 확인하는 테스트는 대부분 깨지기 쉬움
    • 실제 시스템이 아니기 때문에 상호작용이 변하게 되면 테스트가 실패할 수 있음
  • 해당 상호 작용의 부작용이 외부 환경에 보이는 경우에만 목이 괜찮음

 

유지 보수성 지표로 스타일 비교하기

유지비 측정 기준
  • 테스트를 이해하기 얼마나 어려운지
  • 테스트를 실행하기 얼마나 어려운지

 

출력 기반 테스트
  • 가장 유지보수 하기 용이함
  • 입력 공급과 출력 확인 두 가지로 요약할 수 있기 때문에, 항상 짧고 간결함

 

상태 기반 테스트
  • 유지보수 하기 쉽지 않음
  • 더 많은 공간을 검증에 사용하기 때문
  • 헬퍼클래스를 사용하거나, 동등 멤벌ㄹ 정의하여 단순화할 수 있음

 

통신 기반 테스트
  • 유지보수 하기 어려움
  • 테스트 대역과 상호 작용 검증을 설정해야 함