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.