체크 리스트

  • 테스트 클래스의 위치
  • 테스트 메소드 작성 방식
  • 테스트 케이스 접근 방식
  • TDD의 한계

테스트 클래스의 위치

  • 테스트 대상 소스와 테스트 클래스를 같은 곳에
    • src/bank/Account.java + src/bank/AccountTest.java
    • 테스트 클래스와 같은 패키지에 놓는 가장 기본적인 형태
    • 간단한 테스트를 만들 때 외에는 잘 사용하지 않는다.

    • 장점
      • 클래스 이름 규칙을 잘 정했을 경우 테스트 클래스를 찾기 쉽다.
    • 단점
      • 패키지 내에 제품 코드 클래스와 테스트 클래스가 함께 존재하기 때문에 혼란을 줄 수 있다. 배포 시에 테스트 클래스만 발췌해야 하는 불편함이 있다.
    • 선호도
      • 낮음
  • 테스트 클래스는 하위 패키지로
    • src/bank/Account.java + src/bank/test/AccountTest.java
    • 대상 소스의 하위에 테스트 패키지를 만든는 방법

    • 장점
      • 테스트 코드가 가까운 곳에 위치한다.
    • 단점
      • 이미 하위 패키지가 존재할 경우에는 혼란스러울 수 있다. 테스트 클래스와 제품 클래스를 따로 분리하여 배포하는 데 어려움이 있다.
    • 선호도
      • 낮음, 지금은 거의 사용하지 않는다.
  • 최상위 패키지를 분리
    • /src/main/Account.java + /src/test/AccountTest.java
    • 최상위 패키지부터 업무 코드와 테스트 코드를 분리해서 작성할 수 있게 만들어 준다.

    • 장점
      • 업무 코드와 테스트 코드가 섞일 염려가 없다. 테스트 코드만 분리해내기 쉽다.
    • 단점
      • default나 protected로 선언된 메소드들에 대해 테스트 코드를 작성할 수 없다. 어쨌든 배포 시나 패키징시에 test 패키지 이하를 따로 발췌해내야 한다.
    • 선호도
      • 보통
  • 테스트를 프로젝트로 분리
    • Bank Buisiness Project + Bank Buisiness Test Project
    • 외부 라이브러리 의존 관계를 좀 더 확실하게 구분하고자 프로젝트 단위로 분리
    • 컴포넌트식 개발과 테스트에 흔히 쓰이는 방식

    • 장점
      • 제품 코드와 테스트 케이스 코드의 외부 라이브러리 의존 관계를 명확히 분리해낸다.
      • 제품 코드와 테스트 코드를 프로젝트 레벨로 개별적 배포가 용의
    • 단점
      • 환경 구성 방법이 IDE에 의존적이 된다. Ant 스크립트 등의 외부 툴을 함께 쓸 경우, 클래스패스 관련해서 스크립트 작성이 번거롭다.
    • 선호도
      • 프로젝트 라이브러리에 대해 상세화된 전권행사(Detailed Full control)을 원하는 개발자에게 추천
  • Maven 스타일
    • 패키지 구조
      • src/main/java + src/main/resources + src/test/java + src/test/resources
    • 실제 폴더 구조에는 클래스 파일 생성 경로
      • target/classes + target/test-classes
    • src/main/java
      • 제품 코드가 들어가는 위치
    • src/main/resources
      • 제품 코드에서 사용하는 각종 파일, XML 등의 리소스 파일들
    • src/test/java
      • 테스트 코드가 들어가는 위치
    • src/test/resources
      • 테스트 코드에서 사용하는 각종 파일, XML 등의 리소스 파일들
    • 장점
      • 제품 코드에 필요한 리소스와 테스트에 사용하는 리소스를 분리해서 관리하기에 편하다.
      • 메이븐 방식으로 구성된 프로젝트를 접할 때 어색하지 않다.
    • 단점
      • 이런 형태의 구조를 처음 접할 경우 적응하는 데 시간이 걸린다.
    • 선호도
      • 보통
      • Maven 사용자에게는 회피할 수 없는 구조

테스트 메소드 작성 방식

  • 테스트 대상 메소드와 이름을 1:!로 일치
    • 테스트 대상 코드
      public int getBalance() {...} 
      
    • 테스트 코드
      @Test
      public void testGetBalance() {...}
      
    • 장점
      • 테스트 메소드의 숫자가 적어져서 보기 편하고, 대상이 되는 클래스의 메소드와 1:1로 연관지어 생각할 수 있다.
    • 단점
      • 추가적인 테스트 케이스가 하나의 테스트 메소드 내에 전부 존재하게 만들 경우, 메소드 내의 초반 테스트 단정문이 실패하면, 뒤쪽 테스트 케이스들은 실행되지 않는다.
      • 이럴 경우 성공하는 케이스와 실패하는 중간중간 섞여 있을 수 있지만 구별해낼 수 없다.
  • 테스트 대상 메소드의 이름 뒤에 추가적인 정보 기재
    • 테스트 대상 코드
      public int withdraw() {...} 
      
    • 테스트 코드
      @Test
      public void testWithdraw_마이너스통장인출() {...}
      @Test
      public void testWithdraw_잔고가0원일때() {...}
      
    • 장점
      • 더 다양한 케이스별로 성공/실패를 알 수 있다.
      • 케이스마다 독립적으로 수행할 수 있어 오류의 가능성이 좀 더 줄어든다.
    • 단점
      • 테스트 케이스만큼 메소드를 만들기 때문에 메소드 숫자가 많아진다.
      • 테스트 메소드 이름을 짓는데 상당한 요령이 필요하다.
      • 케이스마다 리소스 초기화(setup) 작업이 필요하다.
  • 테스트 시나리오에 집중
    • 테스트 대상 코드
      • 특정한 메소드를 대상으로 하기보다는 테스트 시나리오가 대상이 된다.
    • 테스트 코드
      @Test
      public void vip고객이_인출할때_수수료계산() {...}
      @Test
      public void 일반고객이_인출할때_수수료계산() {...}
      
    • 통합 테스트나 사용자 테스트에 가까운 형태로 테스트 케이스를 만들 필요가 있을 때 사용
    • 작성 대상 클래스의 메소드 구현을 위해 사용한다기보다는 테스트 시나리오에 집중해서 대상 클래스 자체의 통합적인 기능 테스트
    • 특성상 일반적으로 선조건 -> 수행 -> 예상 결과 식의 시나리오를 갖는다

    • 장점
      • 테스트 케이스를 시나리오에 따라 체계적으로 작성할 수 있다.
      • 테스트 클래스를 하나의 업무단위 테스트 단위처럼 문서화할 수 잇다.
    • 단점
      • 테스트 대상 클래스의 단위 메소드 구현 시에 사용하기에는 다소 무리가 따른다.

테스트 케이스 작성 접근 방식

  • 무엇을 테스트 케이스로 작성할 것인가?
    • 해피데이 시나리오
      • 정상적인 흐름일 때 동작해야 하는 결과값을 선정해 놓는 것
    • 블루데이 시나리오
      • 발생할 수 있는 예외나 에러 상황에 대한 결과값을 적어 사용
    • 다음과 같은 질문을 해보자
      • 결과가 옳은가?
      • 모든 경계조건이 옳은가?
      • 역(inverse) 관계를 확인할 수 있는가?
      • 다른 수단을 사용해서 결과를 교차확인할 수 있는가?
      • 에러 조건을 강제로 만들어 낼 수 있는가?
      • 성능이 한도 내에 있는가?

TDD의 한계

  • 동시성 문제
    • 동시성이 걸려 있는 코드에 대한 테스트 케이스 작성은 테스트 자체를 무결하게 유지하기 어렵다.
  • 접근제한자(private/ protected 메소드)
    • 테스트 클래스에서 private 메소드에 대한 접근이 안되는 경우
    • 현재는 ‘public 메소드만 테스트해도 무방하다’는 경향이 있다. 그 이유는 public 메서드에서 해당 private 메서드를 호출해서 사용하기 때문이다.

** 참고 서적: 테스트주도개발 TDD실천법과 도구