JUnit 기초

기본적인 JUnit 설치 및 사용법은 Getting started를 참고한다.

테스트 선언

테스트 메소드는 public void 이면서 입력 인자가 없어야 한다. 다음의 테스트는 두개의 인자가 같은지 확인한다.

import static org.junit.Assert.assertEquals;
import org.junit.Test;

public class SampleTest {
  @Test
  public void testMethod() {
    assertEquals(5, 2+3);
  }
}

단언문

assert~ 형태의 메소드를 말한다. org.junit.Assert 클래스에 public static 메서드로 정의되어 있다.

// 첫번째 인자는 테스트가 실패할 경우 출력되는 메시지다. (생략 가능)
assertArrayEquals("failure - byte arrays not same", "trial".getBytes(), "trial".getBytes());
assertEquals("failure - strings are not equal", "text", "text");
assertFalse("failure - should be false", false);
assertNotNull("should not be null", new Object());
assertNotSame("should not be same Object", new Object(), new Object());
assertNull("should be null", null);
Integer aNumber = Integer.valueOf(768);
assertSame("should be same", aNumber, aNumber);

자세한 예제는 AssertionsAssert JavaDoc문서를 참고한다.

assertThat

assertThat 메소드와 Hamcrest를 사용해서 기본 단언문을 확장할 수 있다. Hamcrest는 테스트에 유용한 다양한 Matcher를 제공한다. 자세한 사항은 Tutorial을 참고한다.

  // Core Hamcrest Matchers with assertThat
  @Test
  public void testAssertThatHamcrestCoreMatchers() {
    assertThat("good", allOf(equalTo("good"), startsWith("good")));
    assertThat("good", not(allOf(equalTo("bad"), equalTo("good"))));
    assertThat("good", anyOf(equalTo("bad"), equalTo("good")));
    assertThat(7, not(CombinableMatcher.<Integer> either(equalTo(3)).or(equalTo(4))));
    assertThat(new Object(), not(sameInstance(new Object())));
  }

@Before, @After

@BeforeClass, @Before, @After, @AfterClass 어노테이션을 사용해서 테스트를 수행하기 전과 후에 수행되는 메소드를 지정할 수 있다.

@BeforeClass
public static void setUpClass() throws Exception {
  // 클래스에 정의된 테스트가 실행되기 전에 한번 실행된다.
}

@AfterClass
public static void tearDownClass() throws Exception {
  //클래스에 정의된 테스트가 실행된 후에 한번 실행된다.
}

@Before
public void setUpTest() throws Exception {
  //각각의 테스트 메소드가 수행되기 전에 실행된다.
}

@After
public void tearDownTest() throws Exception {
  //각각의 테스트 메소드가 수행된 후에 실행된다.
}

각각의 테스트 메소드는 다음과 같은 순서로 실행된다 :

@BeforeClass
   ↓
@Before → @Test → @After
@Before → @Test → @After
@Before → @Test → @After
   ↓
@AfterClass

@Rule

규칙을 사용하면 테스트 클래스에서 각 테스트 메소드의 동작을 유연하게 추가하거나 재정의 할 수 있다. 자세한 내용은 Rules를 참고한다.

자주 사용되는 유용한 규칙 :

ExpectedException : 에러를 수집한다.
Timeout : 테스트 메소드의 타임아웃을 설정한다.
TemporaryFolder : 임시 파일이나 폴더를 만들 수 있게 해주고, 테스트가 끝나면 자동으로 삭제한다.

예외 처리 설정

expected 구문 사용하는 방법. 간단히 사용하기 좋다.

@Test(expected = IllegalAragumentException.class)
public void exceptionTest() {
  String number = "invalidPhoneNumber";
  Phone phone = new Phone();
  phone.call(number);
}

try-catch 구문을 사용하는 방법. Exception 처리 코드를 작성할 수 있다.

@Test
public void exceptionTest() {
  String number = "invalidPhoneNumber";
  Phone phone = new Phone();
  try {
    phone.call(number);
    fail("invalid phone number");
  } catch (IllegalArgumentException e) {
    assertThat(e.getMessage(), containsString(number));
  }
}

@Rule 어노테이션 사용하는 방법. 코드가 간결해진다.

public class ExceptionTest {

  @Rule
  public final ExpectedException exception = ExpectedException.none();

  @Test
  public void thisTestPasses() {
    // exception이 아무런 Exception을 expect 하고 있지 않을므로 이 테스트는 통과한다.
  }

  @Test
  public void throwsExceptionWithCorrectMessage() {
    // RuntimeException이 발생해야 한다.
    exception.expect(RuntimeException.class);
    // Exception의 메시지는 Hello 라는 문자열을 포함해야 한다.
    exception.expectMessage("Hello");
    // Hi 와 Hello 가 다르므로 이 테스트는 실패한다.
    throw new NullPointerException("Hi");
  }
}

시간 제한 설정

@Test 어노테이션의 timeout attribute를 설정해서 테스트 메소드의 수행 시간을 제한할 수 있다.

@Test(timeout=3000)
public void timeoutTest() {
}

@Rule을 사용해서 모든 테스트 메소드에 같은 타임아웃을 설정할 수 있다. 다음의 두 테스트는 JUnit에 의해 강제 종료된다.

@Rule
public MethodRule timeout = new Timeout(20);

@Test
public void loop1() {
  while (true) {};
}

@Test
public void loop2() {
  while (true) {};
}

참고자료