Junit-설정 방법을 한 번 실행


답변:


205

사용 @BeforeClass이 고전적인 솔루션 이라는 @assylias에 동의하지만 항상 편리한 것은 아닙니다. 주석이 달린 메서드 @BeforeClass는 정적이어야합니다. 테스트 케이스의 인스턴스가 필요한 일부 테스트의 경우 매우 불편합니다. 예를 들어 @Autowired스프링 컨텍스트에 정의 된 서비스와 함께 작동 하는 데 사용 하는 스프링 기반 테스트입니다 .

이 경우 개인적 setUp()으로 @Before주석이 달린 일반 메서드를 사용 하고 사용자 지정 static(!) boolean플래그를 관리합니다 .

private static boolean setUpIsDone = false;
.....
@Before
public void setUp() {
    if (setUpIsDone) {
        return;
    }
    // do the setup
    setUpIsDone = true;
}

10
왜 그것이 정적이어야하는지에 대한 Kenny Cason의 코멘트에 추가합니다. JUnit이 각 @Test 메소드에 대해 테스트 클래스의 새 인스턴스를 인스턴스화하므로 정적이어야합니다. 인스턴스 변수는 정적이 아닌 경우 각 인스턴스에 대해 기본값 (false)으로 재설정됩니다. 자세한 정보는 다음을 참조하십시오 : martinfowler.com/bliki/JunitNewInstance.html
dustin.schultz 2014

2
이것은 setUp()메서드가 수퍼 클래스 에있는 경우를 제외하고 작동 합니다.이 문제를 해결하기 위해 아래 에 답변 을 게시했습니다 .
Steve Chambers

4
나는 이것을 84k rep을 가진 누군가에게 말하기를 주저하지만, BeforeClass는 실제로 질문에 대답하지 않습니다. BeforeClass는 모든 테스트 클래스의 시작 부분에서 실행됩니다. 그러나 OP는 "모든 테스트 전에 한 번만"실행되는 것을 요청했습니다. 제안 된 솔루션이이 작업을 수행 할 수 있지만 모든 테스트 클래스가 "CommonTest"클래스를 확장하도록해야합니다.
mike rodent

1
@mikerodent, IMHO OP는 전체 테스트가 아닌 테스트 케이스 내의 모든 테스트에 대해 질문했습니다. 따라서 귀하의 의견은 관련성이 낮습니다. BTW, 그의 평판이 높더라도 어떤 사람에게도 아무 말도하지 마십시오. 적어도 이것이 내가하는 일이다 :). 그리고 2012 년 8 월 제가 질문에 답했을 때 제 평판은 상당히 낮아졌습니다.
AlexR

내 경우에는 작동하지 않으며 설정에서 초기화 된 변수는 각 테스트 후 재설정되므로 한 번만 초기화하는 것은 의미가 없습니다.
Aphax 2017 년

89

당신은 사용할 수 있습니다 주석 :BeforeClass

@BeforeClass
public static void setUpClass() {
    //executed only once, before the first test
}

12
나는 이것을 사용할 수 없습니다. getClass ()와 같은 비 정적 구성 요소를 기반으로하는 몇 가지 설정 메서드가 있습니다.
Bober02

1
@ Bober02 BeforeClass는 실제로 정적이어야합니다. 그것을 사용할 수 없다면 다른 대답이 해결 방법을 제공합니다.
assylias

2
물론 TheClassYouWant.classgetClass () 호출 대신 사용할 수 없습니까? 이것은 실제 Java : String.class.getName().
stolsvik


1
@mikerodent 나는 질문을 "수업의 모든 테스트"로 이해했습니다.하지만 당신이 맞습니다. OP가 원하는 것이 아닐 수도 있습니다.
assylias

29

JUnit 5에는 이제 @BeforeAll 주석이 있습니다.

주석이 달린 메서드가 현재 클래스 또는 클래스 계층 구조의 모든 @Test 메서드보다 먼저 실행되어야 함을 나타냅니다. JUnit 4의 @BeforeClass와 유사합니다. 이러한 메서드는 정적이어야합니다.

JUnit 5의 라이프 사이클 주석이 마침내 제대로 된 것 같습니다! 보지 않고도 사용할 수있는 주석을 추측 할 수 있습니다 (예 : @BeforeEach @AfterAll).


6
그것은 같은 문제를 @BeforeClass가지고 있어야합니다 static. IMO @AlexR의 솔루션이 더 좋습니다.
zengr

@zengr은 당신과 동의하는 경향이 있습니다. 제가 AlexR에게 말했듯이 그의 솔루션은 한 번만 실행되는 경우 CommonTest 클래스에서 하위 클래스로 모든 테스트 클래스를 요구합니다. 그러나 간단 할 수있는 한 간단합니다. IMHO는 언어에서 간단한 메커니즘을 사용할 수있을 때 "멋진"프레임 워크 제공 솔루션을 사용해서는 안됩니다. 물론 타당한 이유가 없다면. 또한 "그것이 주석에 적힌대로한다"라는 이름과 함께 그의 간단한 것을 사용하면 가독성에 도움이됩니다.
마이크 설치류

다시 말하지만, IMHO는 "AfterAll"어노테이션을 갖는 것에 대한 훨씬 더 많은 정당화가있는 것 같습니다. 모든 테스트가 완료되었을 때 감지하는 메커니즘을 고안하는 것은 매우 어렵고 인위적입니다. 반대로, 물론 순수 주의자들은 아마도 "최종 정리"를 할 필요가 없다고 말할 것입니다.
마이크 설치류

각각 테스트가있는 여러 모듈이있는 Maven에서 작동합니까?
Mark Boon 2017 년

@mike 설치류, 필자의 경우 각 테스트 전후에 파일 시스템에서 테스트 파일을 설정하고 해체하면 파일에 교착 상태가 발생하는 것 같습니다. 지금은 한 번 설정에 대한 AlexR의 솔루션에 독립적으로 도착했습니다. 이미 설정 및 더티라는 두 개의 정적 플래그가 있습니다. setup ()은 더티 상태가 처음에 감지되거나 설치 실패가 더티 상태로 이어지는 경우 cleanup ()을 호출합니다. 테스트를 실행 한 후 정리하기 위해 다시 실행합니다. 지저분하고 전혀 이상적이지 않으며 빌드 프로세스가 아닙니다. 더 나은 방법을 찾고 있습니다 (jUnit 4.12).
Rebeccah apr.

9

setUp()테스트 클래스의 슈퍼 클래스에 (예를 들어, AbstractTestBase다음과 같이 아래), 허용 대답을 수정할 수 있습니다 :

public abstract class AbstractTestBase {
    private static Class<? extends AbstractTestBase> testClass;
    .....
    public void setUp() {
        if (this.getClass().equals(testClass)) {
            return;
        }

        // do the setup - once per concrete test class
        .....
        testClass = this.getClass();
    }
}

이것은 하나의 비 정적 setUp()방법에 대해 작동 하지만 tearDown()복잡한 반사의 세계로 벗어나지 않고 는 동등한 것을 생산할 수 없습니다 ... 현상금은 할 수있는 사람을 가리 킵니다!


3

편집 : 디버깅하는 동안 모든 테스트 전에 클래스가 인스턴스화된다는 것을 알았습니다. @BeforeClass 주석이 여기에서 최고라고 생각합니다.

생성자에서도 설정할 수 있으며 테스트 클래스 결국 클래스 입니다 . 거의 모든 다른 방법에 주석이 달려 있기 때문에 이것이 나쁜 습관인지 확실하지 않지만 작동합니다. 다음과 같은 생성자를 만들 수 있습니다.

public UT () {
    // initialize once here
}
@Test
// Some test here...

ctor는 정적이 아니기 때문에 테스트 전에 호출됩니다.


0

이 솔루션을 사용해보십시오 : https://stackoverflow.com/a/46274919/907576 :

@BeforeAllMethods/ @AfterAllMethods주석 모든 주입 값을 사용할 수있는 인스턴스 환경에서 테스트 클래스의 모든 방법을 실행할 수 있습니다.


타사 라이브러리에 의존합니다.
Andrew

0

내 더러운 해결책은 다음과 같습니다.

public class TestCaseExtended extends TestCase {

    private boolean isInitialized = false;
    private int serId;

    @Override
    public void setUp() throws Exception {
        super.setUp();
        if(!isInitialized) {
            loadSaveNewSerId();
            emptyTestResultsDirectory();
            isInitialized = true;
        }
    }

   ...

}

모든 testCases의 기본 기반으로 사용합니다.


public class TestCaseExtended extends TestCase {private static boolean isInitialized = false; 개인 정적 TestCaseExtended caseExtended; private int serId; @Override public void setUp () throws Exception {super.setUp (); if (! isInitialized) {caseExtended = new TestCaseExtended (); caseExtended.loadSaveNewSerId (); caseExtended.emptyTestResultsDirectory (); isInitialized = true; }}
Obi Two

0

각 하위 테스트에서 설정되고 확인 된 변수의 선언을 강제하지 않으려면이를 SuperTest에 추가하면됩니다.

public abstract class SuperTest {

    private static final ConcurrentHashMap<Class, Boolean> INITIALIZED = new ConcurrentHashMap<>();
    protected final boolean initialized() {
        final boolean[] absent = {false};
        INITIALIZED.computeIfAbsent(this.getClass(), (klass)-> {
            return absent[0] = true;
        });
        return !absent[0];
    }
}



public class SubTest extends SuperTest {
    @Before
    public void before() {
        if ( super.initialized() ) return;

         ... magic ... 
    }

}

0

이 문제를 다음과 같이 해결했습니다.

당신에 추가 자료 추상 클래스 (당신이 드라이버를 초기화 I 평균 추상 클래스 setUpDriver () 코드의이 부분 방법) :

private static boolean started = false;
static{
    if (!started) {
        started = true;
        try {
            setUpDriver();  //method where you initialize your driver
        } catch (MalformedURLException e) {
        }
    }
}

이제 테스트 클래스가 기본 추상 클래스 에서 확장되는 경우 -> setUpDriver () 메서드가 첫 번째 @Test 전에 실행될 때마다 번만 실행됩니다.


0

Spring의 @PostConstruct 메서드를 사용하여 모든 초기화 작업을 수행하고이 메서드는 @Test가 실행되기 전에 실행됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.