JUnit 혼란 : 'Extends TestCase'또는 '@Test'?


152

JUnit의 올바른 사용 (또는 적어도 문서)이 매우 혼란 스럽다는 것을 알았습니다. 이 질문은 향후 참조 및 실제 질문으로 사용됩니다.

내가 올바르게 이해했다면 JUnit 테스트를 만들고 실행하는 두 가지 주요 접근법이 있습니다.

접근법 A (JUnit 3 스타일) : TestCase를 확장하는 클래스를 작성하고 단어로 테스트 메소드를 시작하십시오 test. 클래스를 JUnit 테스트 (Eclipse에서)로 test실행 하면 단어 로 시작하는 모든 메소드 가 자동으로 실행됩니다.

import junit.framework.TestCase;

public class DummyTestA extends TestCase {

    public void testSum() {
        int a = 5;
        int b = 10;
        int result = a + b;
        assertEquals(15, result);
    }
}

접근법 B (JUnit 4 스타일) : '일반'클래스 @Test를 작성하고 메소드 앞에 주석을 추가하십시오 . 단어로 메소드를 시작할 필요는 없습니다 test.

import org.junit.*;
import static org.junit.Assert.*;

public class DummyTestB {

    @Test
    public void Sum() {
        int a = 5;
        int b = 10;
        int result = a + b;
        assertEquals(15, result);
    }
}

두 가지를 혼합하는 것은 좋은 생각이 아닌 것 같습니다. 예를 들어이 stackoverflow question을 참조하십시오 .

이제 내 질문 :

  1. 선호하는 방법은 무엇입니까 , 아니면 언제 다른 방법을 사용합니까?
  2. 접근법 B는에서와 같이 @Test 주석을 확장하여 예외 테스트를 허용합니다 @Test(expected = ArithmeticException.class). 그러나 접근법 A를 사용할 때 예외를 어떻게 테스트합니까?
  3. 접근법 A를 사용할 때 다음과 같이 테스트 스위트에서 여러 테스트 클래스를 그룹화 할 수 있습니다.

    TestSuite suite = new TestSuite("All tests");
    suite.addTestSuite(DummyTestA.class);
    suite.addTestSuite(DummyTestAbis.class);

    그러나 이것은 각 테스트 클래스가 TestCase를 서브 클래스 화해야하기 때문에 접근법 B와 함께 사용할 수 없습니다. 접근법 B에 대한 테스트를 그룹화하는 올바른 방법은 무엇입니까?

편집 : JUnit 버전을 두 가지 접근법 모두에 추가했습니다.


나는 extends TestCase각각의 테스트 @Test에 혼란을주기 위해 주석을 달았다 . :)
EM-Creations

답변:


119

구별은 다소 쉽습니다.

  • 확장 TestCase은 단위 테스트가 JUnit 3에서 작성된 방식입니다 (물론 여전히 JUnit 4에서 지원됨).
  • @Test주석을 사용하는 것은 JUnit 4에서 소개 한 방식입니다.

JUnit 3 (또는 Java 5 이전의 Java 버전)과의 호환성이 필요하지 않은 경우 일반적으로 주석 경로를 선택해야합니다. 새로운 방법에는 몇 가지 장점이 있습니다.

JUnit 3에서 예상되는 예외를 테스트하려면 TestCase텍스트를 명시 적으로 작성해야합니다.

public void testMyException() {
  try {
    objectUnderTest.myMethod(EVIL_ARGUMENT);
    fail("myMethod did not throw an Exception!");
  } catch (MyException e) {
    // ok!
    // check for properties of exception here, if desired
  }
}

JUnit 5 는 또 다른 API 변경을 도입했지만 여전히 주석을 사용합니다. 새로운 @Test주석은 org.junit.jupiter.api.Test"오래된"JUnit 4는 org.junit.Test이지만 JUnit 4와 거의 동일하게 작동합니다.


도움이되고 철저한 답변이지만 "예외 메시지 확인"을 완전히 이해하지 못합니다. 하드 코딩 된 문자열을 검사하는 것은 유지 관리의 악몽이 될 것입니다. "특정 예외 유형의 속성 확인"을 의미 했어야합니다.
thSoft

3
@thSoft : 자주 사용되는 것은 아니지만 때로는 예외 방법에 문제 필드가 언급되어 있는지 확인하고 싶습니다. 그렇다면 간단한 assertTrue(e.getMessage().contains("foo"))것이 유용 할 수 있습니다.
Joachim Sauer

1
JUnit4에서도 메시지 또는 예외의 다른 속성 (예 : 원인)을 확인해야 할 때 중요한 관용구입니다. 이 expected방법은 유형 만 확인합니다.
Yishai

@Yishai : 사실이지만, 메소드가 문제가있는 입력에 대해 올바른 유형의 예외를 던지면 대부분 만족합니다.
Joachim Sauer

이러한 이유로 JUnit 5는 예외 테스트를 크게 변경했습니다. assertThrows () 환상적 :-)
Marcus K.

25

JUnit 4 (Annotation approach)가 더 유연하다는 것을 선호합니다.

JUnit 4에서 테스트 스위트를 빌드하려면 다음과 같이 모든 테스트를 그룹화하는 클래스를 작성해야합니다.

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;


@RunWith(Suite.class)
@SuiteClasses({
    Test1.class,
    Test2.class,
    Test3.class,
    Test4.class
})public class TestSuite
{
 /* empty class */
}

15

귀하의 질문에 대답하지 않은 부분이 있습니다. "접근 B에 대한 테스트를 그룹화하는 올바른 방법은 무엇입니까?"

공식적인 대답은 @RunWith (Suite.class)로 클래스에 주석을 달고 @ Suite.SuiteClasses 주석을 사용하여 클래스를 나열한다는 것입니다. 이것이 JUnit 개발자가하는 방법입니다 (수트의 모든 클래스를 수동으로 나열). 여러 가지 방법으로이 접근 방식은 스위트 전과 스위트 후 동작을 추가하는 것이 사소하고 직관적이라는 점에서 개선되었습니다 (@RunWith로 주석이 달린 클래스에 @BeforeClass 및 @AfterClass 메소드를 추가하면 기존 TestFixture보다 훨씬 낫습니다). ).

그러나 주석을 사용하면 클래스 목록을 동적으로 만들 수 없으므로 해당 문제를 해결하는 것이 약간 추악합니다. Suite 클래스를 서브 클래 싱하고 서브 클래스에서 클래스 배열을 동적으로 작성하여 Suite 생성자에 전달해야하지만, Suite의 다른 서브 클래스 (예 : 카테고리)가 작동하지 않고 본질적으로 작동하지 않는 불완전한 솔루션입니다 동적 테스트 클래스 콜렉션을 지원하지 않습니다.


1
이것을 위해 +1. TestSuite에 테스트를 추가하는 동적 솔루션을 작성하는 작업을 시작한 후 각 테스트에서 TestCase를 확장해야했습니다. 이것은 예상되는 예외를 정의하기 위해 JUnit4 주석을 사용한 이전의 작업 단위 테스트를 중단했습니다. Test Suite를 동적으로 채우는 방법에 대한 나의 검색으로
인해이

4

JUnit 4를 사용해야합니다. 더 좋습니다.

많은 프레임 워크에서 JUnit 3.8 지원이 중단되었습니다.

이것은 Spring 3.0 참조 문서에서 가져온 것입니다.

[경고] 레거시 JUnit 3.8 클래스 계층 구조는 더 이상 사용되지 않습니다

일반적으로 새로운 것을 시작할 때는 항상 최신의 안정적인 프레임 워크 릴리스를 사용해야합니다.


1
  1. "선호하는"접근 방식은 Junit 4 이후에 도입 된 주석을 사용하는 것입니다.

  2. 간단한 try / catch 블록을 사용할 수 있습니다.


public void testForException() {
    try {
        Integer.parseInt("just a string");
        fail("Exception should have been thrown");
    } catch (final Exception e) {
        // expected
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.