[Unit testing(단위 테스트)-블라디미르 코리코프 저] 한 장 요약

2022. 12. 4. 14:37북리뷰/한 장 요약

728x90

단위 테스트 목표

  • 프로젝트 지속성 확장성의 핵심 -> 장기적 개발 속도 유지 가능
  • 기반 코드 리펙터링시 테스트도 리펙터링
  • 품질 특정을 위한 지표(코드 커버리지, 분기 커버리지) 맹신 X 참고용으로만,
    • 100퍼센트 안채워도 됨

단위 테스트란 무엇인가

  • 고전파 : 난수성, 외부API, DB 시스템 등에만 Mock 사용
    • 엔드 투 엔드
    • 테스트 간 의존성 높음
    • 동작 단위 테스트 용이
  • 런던파 : 모든 의존성에 MOCK 사용
    • 테스트 입자성이 좋음
    • 과도한 명세

단위 테스트 구조

  • Given when then 구조 좋아용
  • 테스트 내 if문 피하기
  • 테스트 간 결합도 낮춰야
  • 명명법 : [테스트 대상 메서드]_[시나리오]_[예상 결과]
    • 너무 엄격하지 명명 지침 따르지 말것 : 중요한건 가독성
    • 명명시 should be 사용 X
  • 비슷한 테스트끼리 그룹화 가능

좋은 단위 테스트 4대 요소

  • 좋은 단위 테스트 특성
    • 회귀 방지
      • 수정 후 버그 방지
      • 테스트가 최대한 많은 코드를 실행해야
    • 리펙터링 내성
      • 거짓 양성(문제 없는데 테스트 실패하는 것) 없애야 : 테스트 코드의 신뢰 하락
    • 빠른 피드백
    • 유지 보수성
  • 거짓 양성 원인 : 해결법
    • 구현 세부 사항을 많이 결합 : 테스트 분리
      • 코드 내부 작업과 테스트 사이를 멀리 떨어트림
      • 최종 결과를 목표로

목과 테스트 취약성

  • 테스트 대역 유형
    • 목 : 외부 상호작용을 모방 : sut 상태 변경을 위한 의존성 호출 예 ) 이메일 발송
    • 스텁 : 내부 상오작용을 모방 : 입력 데이터를 얻기 위한 의존성 호출 예 ) 데이터 검색
  • 스텁과 상호작용을 검증 X
  • 목 + 스텁이면 대체적으로 목이라 부름
  • 목,스텁 개념은 명령 조회 분리(CQS)dp rhksfus
  • 테스트는 어떻게가 아니라 무엇에 중점을 둬야
  • 캡슐화 중요
    • 세부 구현을 숨겨 내부 손상 위험 방지
  • 시스템 내부 통신은 구현 세부사항
    • ex) Service - repo

단위 테스트 스타일

  • 단위 테스트 스타일
    • 출력 기반 테스트
    • 상태 기반 테스트
    • 통신 기반 테스트
  • 출력 기반 : 테스트 대상에 입력하고 출력을 점검
    • 반환값 검증
  • 상태 기반 :
    • 작업 완료 후 시스템 상태 확인
  • 통신 기반 : 올바르게 호출하는가
  • 최대한 출력 기반 테스트 해야
  • 함수형 코어 클래스는 협력자로 작동 X, 작업 결과의 값으로 작동해야

가치 있는 단위 테스트를 위한 리펙터링

  • 코드가 중요하거나 복잡할수록 협력자는 적어야
  • 복잡한 코드가 테스트 코드 작성 1순위
  • 좋지 않는 테스트코드 작성할 바에 차라리 작성하지마
  • SRP 지켜
  • 비즈니스 로직과 오케스트레이션 분리(MVC)
  • 유의성 밌는 모든 전제조건 테스트
  • 유의성 없는 것은 굳이?
  • 비즈니스 로직 파편화 X
  • 추상화를 테스트해야

통합 테스트를 하는 이유

  • 단위 테스트는 도메인 모델 및 알고리즘 위주 : 복잡도와 도메인 유의성 높음
  • 통합 테스트는 컨트롤러 위주 : 협력자 높음
  • 빠르게 실패해야
  • 관리 의존성(DB) : 실제 인스턴스 사용
  • 비관리 의존성(SMTP, Message bus) 목 대체
  • 의존성 추상화 -> 인터페이스 사용
  • 도메인 모델 경계 명시
  • 애플리케이션 내 계층 줄이기
  • 순환 의존 제거
    • 콜백써서 해결
  • 추상화도 과유불급

목처리에 대한 모범 사례

  • 비관리 의존성에만 적용
  • 시스템 끝에 있는 의존성 상호ㅈ가용 검증
  • 단위 테스트에서는 사용 X
  • 목 호출 수 수시로 확인
  • 보유 타입만 목 처리
    • adapter 작성
    • 기본 라이브러리 복잡성 추상화
    • 필요 기능만 노출
    • 도메인 언어를 사용해 수행

데이터베이스 테스트

  • 형상 관리 시스템에 DB 유지
  • 개발자 마다 별도 DB 인스턴스 사용
  • DB 배포에 마이그레이션 기반 방식 적용
  • 모델 DB와 운영 DB 분리
  • 참조 데이터도 스키마임
  • 원자적 업데이트 세트 구성(트랜젝션 작업 단위)
  • 트랜젝션/작업 단위 재사용 X
  • 통합 테스트에서 최소 3개 트랜젝션/작업 단위 사용(준비, 실행, 검증)
  • 통합 테스트를 순차적으로 실행
  • 테스트 실행 간 잔여 데이터 제거
  • 종료 단계 필요 X , 준비 구절에서 구현
  • 참조 데이터는 제거 X
  • 인메모리 DB 사용 X
  • 팩토리 메서드로 기본값 정의
  • DB 쓰기 테스트는 필수
  • 읽기 테스트는 선택
  • Repository 테스트는 비추

단위 테스트 안티 패턴

  • private method 테스트 안해도 돼
    • private method가 너무 복잡하면 별도 클래스 추출해야
  • private field 노출 X
  • 테스트 때문에 접근 제한자 바꾸지 마
  • 도메인 구현 내용 노출 X
  • 예산 결과 하드코딩 해도 좋아
  • 테스트코드와 main 코드 혼재 X
  • 구체 클래스 목 처리 X
  • 시간 처리 X
  • now 쓰지 말고 명시적 의존 시간 주입
728x90