[xUnit 테스트 패턴] 19장 - xUnit 기본 패턴


19장 - xUnit 기본 패턴

테스트 메소드

  • 각 테스트를 어떤 클래스의 단일 메소드 형태로 만든다.

동작 원리 : 테스트 메소드

  • 단순 성공 테스트
    • 픽스처 설치, 테스트 대상 시스템 실행, 결과 검증을 순서대로 실행
  • 기대 예외 테스트
    • 에러 처리 코드 작성 후 해당 코드에 도달하면 테스트 성공, 아니면 테스트 실패
  • 생성자 테스트
    • 객체를 생성한 후에 그 객체의 속성에 대해 단언문을 건다.

사용 이유 : 테스트 메소드

  • 시스템 문서화로서의 기능이 좋아짐

구현 : 테스트 메소드

변형 : 단순 성공 테스트

  • SUT 객체 생성 -> 테스트하고 싶은 메소드 실행 -> 기대 결과 값 발생했는지 단언
    • 발생 가능한 예외 처리는 테스트 자동 프레임워크에서 처리

변형 : 기대 예외 테스트

  • 에러가 발생할 수 있게 테스트 픽스처를 설치하고 SUT를 실행
  • SUT가 발생할 것으로 예상되는 모든 종류의 예외에 대해 기대 예외 테스트를 작성해야 한다.
  • 테스트 스텁으로 SUT의 간접 입력을 제어해 적절한 에러 발생 시킴

변형 : 생성자 테스트

  • 다른 테스트 안에 생성자 로직 검증을 같이 포함시키는 것보다 결함 국소화가 좋아진다.
  • 필수 초기화 값은 동등 단언문을 써서 올바른 값을 명시해준다.

변형 : 의존 초기화 테스트

  • 제품 코드에서 의존 컴포넌트를 참조하는 속성이 진짜 DOC를 가리키는지 보장해줘야 한다.
  • 생성자 테스트와는 다른 테스트 메소드에 둔다.

4단계 테스트

  • 테스트를 순서대로 실행되는 네 부분으로 구성한다.

동작 원리 : 4단계 테스트

  • 1단계 : 픽스처 설치
  • 2단계 : SUT 실행
  • 3단계 : 결과 검증
  • 4단계 : 픽스처 해제

사용 이유 : 4단계 테스트

  • 테스트의 의도를 쉽게 보여준다.
  • 문서로서의 테스트 가능
  • 결함 국소화

구현 : 4단계 테스트

  • 모든 테스트를 독립적으로 만든다.
  • 테스트 4단계 모두가 테스트 메소드에 들어 있으면 된다.

단언 메소드

  • 기대 결과 값이 제대로 나왔는지를 평가하는 유틸리티 메소드를 호출한다.

동작 원리 : 단언 메소드

  • 테스트 자동 프레임워크에서 단언 메소드 제공
  • 개발자가 직접 맞춤 단언문 구현

사용 이유 : 단언 메소드

  • 재사용 가능한 테스트 유틸리티 메소드로 테스트 코드 중복, 버그투성이 테스트를 피하게 해준다.

구현 : 단언 메소드

내장 단언 메소드 호출

  • 프레임워크에서 제공되는 테스트케이스 상위클래스에서 단언 메소드를 상속 받는다.
    • 단언 메소드가 들어있는 Assert 클래스를 상속받은 테스트케이스 상위클래스를 제공한다.
  • 전역에서 접근 가능한 클래스나 모듈로 제공된다.
  • 단언 메소드가 믹스인이나 매크로 형태로 제공되기도 한다.

올바른 단언문 선택하기

  • fail() 같은 단일 결과 단언문
    • 항상 같은 방식으로 동작하기 때문에 인자를 받지 않는다.
  • assertNotNull or assertTrue 같은 결과 지정 단언문
    • 하나의 인자를 결과와 비교한다.
  • assert_raised 같은 기대 예외 단언문
    • 코드 블록과 한 개의 기대 예외를 인자로 받는다.
  • assertEqual(expected, actual) 같은 동등 단언문
    • 두 개의 객체나 값이 같은지를 비교
  • assertEqual(expected, actual, tolerance)) 같은 퍼지 동등 단언문
    • 허용 오차(tolerance)나 비교 마스크로 두 값이 충분히 가까운지 검사

단언 메시지

  • 단언 메소드를 호출할 때 내용을 설명하는 문자열 인자를 포함한다.

동작 원리 : 단언 메시지

  • 실패 로그에 추가될 문자열을 생략 가능한 인자 형태로 받는다.

언제 쓸 것인가 : 단언 메시지

  • 테스트 메소드별로 하나의 단언문
    • 테스트 메소드로 알 수 있어 따로 추가하지 않음
  • 테스트 안에서 여러 개의 단언 메소드를 호출 시 단언문 마다 사용
    • 어떤 단언문이 실패했는지 알기 위해 단언문 마다 사용

변형 : 기대를 보여주는 메시지

  • “무엇이 발생했어야 헀는가?”에 대한 설명을 추가

변형 : 인자를 보여주는 메시지

  • assertTrue 같은 결과 지정 단언문은 실패시 인자를 보여주면 왜 테스트기 실패했는지 알 수 있다.

테스트케이스 클래스

  • 관련 있는 테스트 메소드들을 묶어 하나의 테스트케이스 클래스 안에 둔다.

동작 원리 : 테스트케이스 클래스

  • 일종의 테스트 스위트 팩토리 역할을 해 테스트 메소드별로 테스트케이스 객체를 생성한다.
    • 생성된 모든 객체를 테스트 스위트 객체에 등록해 테스트 실행기에서 모두 실행할 수 있게 한다.

테스트 실행기

  • 테스트 스위트 객체를 생성하고 그 안에 있는 모든 테스트케이스 객체를 실행하는 프로그램을 만든다.

동작 원리 : 테스트 실행기

  • 테스트 실행기는 테스트 나열, 테스트 찾기, 테스트 선택 등을 통해 컴포짓(Composite) 테스트 객체를 얻는다.
  • 테스트 실행기는 테스트 실행 수, 단언문 실패 수, 에러나 예외 발생했는지를 기록했나가 끝나면 결과를 알려준다.

구현 : 테스트 실행기

변형 : 테스트 트리 탐색기

  • 그래픽으로 스위트들의 스위트를 보여주고 사용자가 전체 테스트 스위트 객체나 특정 테스트케이스 객체를 선택해 실행시킬 수 있다.
  • ex) JUnit

테스트케이스 객체

  • 테스트별로 명령 객체를 만든 후 실행하고 싶을 때 run 메소드를 호출한다.

테스트 스위트 객체

  • 표준 테스트 인터페이스를 구현한 컬렉션 클래스를 정의한 뒤, 이를 통해 관련된 테스트케이스 객체들을 실행한다.

동작 원리 : 테스트 스위트 객체

  • 실행시켜야 할 테스트케이스 객체들을 담아둔다.
    • 테스트 실행기에서 테스트 스위트 객체 안에 모든 테스트 실행 가능

테스트 찾기

  • 테스트 자동 프레임워크가 테스트 스위트의 모든 테스트를 알아서 찾는다.

동작 원리 : 테스트 찾기

  • 런타임 리플렉션으로 테스트 스위트 객체에 들어있는 모든 테스트 메소드와 스위트들의 스위트에 들어있는 모든 테스트 스위트 객체를 찾는다.

(메소드 속성으로) 테스트 메소드 찾기

  • JUnit 에서 @Test annotation 으로 테스트 메소드를 찾는다.

테스트 나열

  • 테스트 개발자가 테스트 스위트에 들어갈 모든 테스트를 나열하는 코드를 직접 작성한다.
  • 테스트 찾기를 지원해 줄 수 없는 경우에 대신 쓸 수 있는 방법

테스트 선택

  • 테스트 자동 프레임워크에서 런타임에 테스트의 속성을 보고 실행할 테스트 메소드를 선택한다.
  • 테스트 선택은 동적으로 테스트 중 일부를 선택할 수 있는 방법

구현 : 테스트 선택

변형 : 테스트케이스 클래스 선택

  • 클래스 어노테이션으로 테스트케이스 클래스를 알려줄 수 있다.