본문 바로가기
TREND

JUnit Cookbook

by ojava 2015. 8. 25.
반응형

개발하면서 테스트를 수행하기 위해서 크게 두 가지 방법을 사용했을 것으로 생각된다.

 

가장 간단하게는 디버거를 통해 표현식을 사용하여 데이터를 확인하는 방법.

이 방법을 통해 재 컴파일 없이도 디버깅 표현식을 여러가지로 바꿀 수 있고 디버깅 툴을 이용해

원하는 곳에서 원하는 데이터에 대해 확인할 수도 있다.

 

또는 기본 output stream을 이용하여 테스트 구문을 화면에 출력하는 방법.

이 방법의 경우는 수행 순서 중간 중간에 출력문을 넣어서 실행 순서 파악에 사용하거나

특정 값을 출력해서 정상적인 로직이 수행되었는지를 확인하는 데 사용되었다.

출력구문을 바꾸고 싶을 때 재 컴파일 해야 한다는 문제가 있긴 하지만..

 

위에 제시한 두가지 방법은 모두 결과값에 대해 해석하고 판단할 필요가 있다는 점에서

테스트 수행자에 대한 의존성이 크다.

 

 

Kent Beck과 Erick Gamma에 의해 제안된 JUnit을 이용해서 간단한 Test Case를 만드는 방법에 대해

알아보고 TEST 수행과 예외처리에 대한 내용도 아주 간단하게 알아보자.

 

뭐든 간단하게 알아보는 이유는... 이 내용이 JUnit Cookbook을 번역한 내용이기 때문이다.

그렇다면 이쯤에서 출처를 밝혀두고 내용을 다시 이어서 써보겠다.

 

<출처 : http://junit.sourceforge.net/doc/cookbook/cookbook.htm>

 

 

 

Test Case

 

JUnit을 이용하게 되면 위에 말했던 단점들을 보완한 테스트 수행이 가능하다.

결과값에 대해 테스트 수행자의 판단이 필요하지 않고, 동시에 여러 test의 수행이 가능하다.

JUnit을 이용한 테스트가 필요하다면 이것만 알아두면 된다. (왠지 북치기 박치기가 생각나는 느낌적인 느낌)

 

1. Method에 @org.junit.Test 어노테이션 (annotation)을 붙여라

2. 값에 대한 체크가 필요한 경우, import org.junit.Assert.* 하고 assertTrue() 함수를 호출해라.

   테스트 결과가 성공적인 경우 해당 함수는 return type인 boolean이므로 'true'를 반환한다.

 

이렇게 설명하는 것보다 코드 쓰는게 백배는 빠르게 이해될 것이므로 코드를 당장 붙여넣도록 하겠다.

두 개의 Money에 대한 합을 구한 것, 그리고 그 값과 같은 값을 가지는 새로운 Money 변수를 선언하고

이 둘이 같은 값을 가지는 지 Test하는 코드를 써놓았다고 함.

 

 

@Test public void simpleAdd() {
    Money m12CHF= new Money(12, "CHF"); 
    Money m14CHF= new Money(14, "CHF"); 
    Money expected= new Money(26, "CHF"); 
    Money result= m12CHF.add(m14CHF); 
    assertTrue(expected.equals(result));  <- 값 체크를 위한 assertTrue 함수 호출. 결과값은 boolean 타입
}

 

 

Method Annotation으로 @Test를 추가하였고 (@org.junit.Test가 아닌 것은 import를 해서임)

값 체크를 위해서 assertTrue 함수를 사용하고 있는 것을 확인할 수 있음.

결과는 12+14 = 26 임을 알고있는 것과 같이 true를 반환할 것으로 예상된다.

 

 

 

Fixture

 

유사하거나 또는 동일한 객체를 사용한 두 개 이상의 테스트 수행이 필요한 경우에는?

테스트는 Test Fixture라고 불리는 개체집합에 대해 실행되어져야 한다.

테스트를 작성할 때, 실제 테스트 수행 시간보다 fixture를 세팅하는 코드를 작성하는 데에 많은 시간을 소비하게 된다.

 

기존에 작성했던 생성자를 살펴봄으로써 Fixture 코드를 얼마정도는 더 쉽게 작성할 수 있겠지만,

Fixture 코드를 공유하는 것이 더 많은 시간을 아낄 수 있다.

많은 경우에서, 동일한 Fixture 코드를 각각 다른 테스트 수행에 사용할 수 있다.

각각의 Test case는 약간씩의 다른 메시지 또는 매개변수를 Fixture로 전달하고 다른 결과물들에 대해 체크할 수 있다. 

 

공통의 Fixture를 만들 때, 이것만은 꼭 해야한다.

 

1. Fixture 각각의 파트에 Field를 추가해야 한다.

2. 변수들의 초기화를  선언하는 함수의 경우, @org.junit.Before Annotation을 추가해준다.

3. 할당했던 자원들을 해제하는 함수에는 @org.junit.After Annotation을 추가한다.

 

 

이 역시도 예시를 들어보자면, 12 스위스 프랑 & 14 스위스 프랑 & 28 달러의 서로 다른 조합으로 작업할

몇 가지 Test case를 작성하고자 하는데 그 중 첫번째로 하나의 Fixture를 다음과 같이 만든다.

 

public class MoneyTest { 
    private Money f12CHF; 
    private Money f14CHF; 
    private Money f28USD; 
    
    @Before public void setUp() {     <- Before Annotation을 사용하면 Test보다 먼저 수행된다.
        f12CHF= new Money(12, "CHF"); 
        f14CHF= new Money(14, "CHF"); 
        f28USD= new Money(28, "USD"); 
    }
}

 

 

한 번 Fixture를 준비하고 나면, 원하는대로 많은 Test Case들을 작성할 수 있다.

@Test Annotation을 붙인 많은 테스트 Method들 역시도 추가할 수 있음!

 

 

 

Running Tests

 

정의한 테스트들을 수행하거나 그 결과값들을 확인하는 방법을 알아보자.

 

JUnit은 수행을 위한 일련의 과정을 정의하고 결과값을 보여줄 수 있는 Tool을 제공한다.

콘솔에서 테스트를 수행하고 결과를 보기 위해서 다음과 같은 내용을 수행해보자.

 

Java 프로그램 내에서 수행 : org.junit.runner.JUnitCore.runClasses (TestClass1.class, ...);

Command Line에서 수행 : java org.junit.runner.JUnitCore TestClass1 [... other test classes...]

 

JUnit 이전 버전에서도 호환될 수 있도록 TestRunner를 만들어야 하는 경우에는

static method로 test를 반환하는 함수를 선언해주어야 한다.

 

 

 

Expected Exceptions

 

코드가 예외를 발생시키는 지를 검증하는 방법은 무엇일까.

 

코드가 완벽한지를 검증하는 일반적인 방법은 프로그래밍의 한 부분이다.

예외적인 상황에서 예상대로 코드가 작동하도록 구성하는 것 역시도 확실히 프로그래밍의 일부이다.

 

예를 들어, 아래와 같은 코드가 있다고 하자.

 

new ArrayList<Object>().get(0); 

 

 

이 코드는 IndexOutOfBoundException을 발생시킬 것이 확실하다.

Method에 @Test Annotation을 붙일 때 옵션값으로 expected 파라미터로 예외처리할 Throwable 클래스를 주면

예외처리가 가능하다. 이렇게.

 

 

@Test(expected= IndexOutOfBoundsException.class) public void empty() { 
    new ArrayList<Object>().get(0);    <- 예외를 발생시키는 코드
}

 

 

 

 

 

Cookbook은 진짜 맛보기만 가능한 느낌이네여..

실제 적용은 다음 포스팅에서..

 

반응형