수업 전 Junit (비 정적)


84

Junit이 테스트 파일에서 한 번 함수를 실행하도록하는 모범 사례가 있습니까? 또한 정적이어서는 안됩니다.

@BeforeClass비 정적 기능 처럼 ?

추악한 해결책은 다음과 같습니다.

@Before void init(){
    if (init.get() == false){
        init.set(true);
        // do once block
    }
}

글쎄 이것은 내가하고 싶지 않은 일이며 통합 된 junit 솔루션을 찾고 있습니다.


글쎄, 나는 테스트 파일과 기본 테스트 파일의 상당히 큰 계층 구조를 가지고 있습니다. 하위 테스트 클래스에서이 작업을 재정의 할 가능성이 필요합니다.
Roman

1
나는 많은 매개 변수화 된 테스트 중 첫 번째 만 로그인을 수행 해야하는 동일한 문제가있었습니다.
dokaspar

5
일반 JUnit과 함께 작동하는 "추악한"솔루션은 테어 링 테스트를 고려하지 않습니다.
eskatos

답변:


22

일회성 초기화를 위해 정적 이니셜 라이저를 설정하고 싶지 않고 JUnit 사용에 대해 특별히 신경 쓰지 않는 경우 TestNG를 살펴보십시오. TestNG는 모두 주석을 사용하여 다양한 구성 옵션으로 비 정적 일회성 초기화를 지원합니다.

TestNG에서 이것은 다음과 같습니다.

@org.testng.annotations.BeforeClass
public void setUpOnce() {
   // One time initialization.
}

분해를 위해

@org.testng.annotations.AfterClass
public void tearDownOnce() {
   // One time tear down.
}

JUnit 4 @Before및에 해당하는 TestNG의 @After경우 @BeforeMethod@AfterMethod각각을 사용할 수 있습니다 .


41

간단한 if 문도 잘 작동하는 것 같습니다.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:test-context.xml"})
public class myTest {

    public static boolean dbInit = false;

    @Autowired
    DbUtils dbUtils;

    @Before
    public void setUp(){

        if(!dbInit){

            dbUtils.dropTables();
            dbUtils.createTables();
            dbInit = true;

        }
    }

 ...

1
멋지고 간단합니다! 그러나 @AfterClass모든 테스트가 실행 된 후 해체 되는 비 정적 등가물 을 만들기 위해 단순히 이것을 조정하는 방법을 볼 수 없습니까?
Steve Chambers

1
상속을 사용하는 테스트 클래스에서 작동해야하는이 메서드에 대한 업데이트는 여기 를 참조 하십시오 .
Steve Chambers

36

빈 생성자를 사용하는 것이 가장 쉬운 해결책입니다. 확장 클래스에서 생성자를 계속 재정의 할 수 있습니다.

그러나 그것은 모든 상속에 최적이 아닙니다. 이것이 JUnit 4가 대신 주석을 사용하는 이유입니다.

또 다른 옵션은 factory / util 클래스에 도우미 메서드를 만들고 해당 메서드가 작업을 수행하도록하는 것입니다.

Spring을 사용하는 경우 @TestExecutionListeners주석 사용을 고려해야합니다 . 이 테스트와 같은 것 :

@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({CustomTestExecutionListener.class, 
     DependencyInjectionTestExecutionListener.class})
@ContextConfiguration("test-config.xml")
public class DemoTest {

AbstractTestExecutionListener예를 들어 Spring 에는 재정의 할 수있는이 빈 메서드가 포함되어 있습니다.

public void beforeTestClass(TestContext testContext) throws Exception {
    /* no-op */
}

참고 : NOT 간과 / 미스 DO DependencyInjectionTestExecutionListener사용자를 추가하는 동안 TestExecutionListeners. 그렇게하면 모든 autowire가 null.


+1이 기술은 DbUnit을 사용하고 클래스 당 데이터 세트를 한 번만로드하려고 할 때 내 문제를 해결했습니다
Brad

+1 이것은 완벽합니다 ... 고대 버전의 Spring에 묶이지 않은 사람들에게 적합합니다. :(
Mike Miller

1
이 윌 beforeTestClass()전이나 컨텍스트가 초기화 된 후에 호출?
2015 년

@Dims 컨텍스트 초기화
아난드 Rockzz에게

7

@BeforeAllMethods/ @AfterAllMethods주석을 쉽게 사용 하여 모든 주입 된 값을 사용할 수있는 인스턴스 컨텍스트 (비 정적) 내에서 메서드를 실행합니다.

이를위한 특별한 테스트 라이브러리가 있습니다.

https://mvnrepository.com/artifact/org.bitbucket.radistao.test/before-after-spring-test-runner/0.1.0

https://bitbucket.org/radistao/before-after-spring-test-runner/

유일한 제한 : Spring 테스트 에서만 작동합니다 .

(저는이 테스트 라이브러리의 개발자입니다)


0

나는 시도한 적이 없지만 인수가없는 생성자를 만들고 거기에서 함수를 호출 할 수 있습니까?


이것은 작동 할 것입니다. 문제는이 기본 테스트 클래스를 확장하는 클래스에서이 작업을 재정의 할 가능성이 필요하다는 것입니다
Roman

@Roman : 오, 이제 알겠습니다. 이것을 게시물에 추가하면이 댓글이 훨씬 더 명확 해집니다.
Roman

생성자는 테스트 케이스가있는만큼 여러 번 호출됩니다. 각 테스트 방법에 대해 새로운 Test 클래스 개체가 생성됩니다. 그래서 생성자를 사용하는 것은 여기서 해결책이 아닙니다
manikanta

또한 이미 생성 된 개체에 의존하는 종속성 주입에서는 작동하지 않습니다.
Mike Miller

0

이 기사 에서는이 문제에 대한 두 가지 매우 좋은 해결책에 대해 설명합니다.

  1. 사용자 지정 Runner로 "clean"junit (인터페이스를 사용하지만 @BeforeInstance와 같은 사용자 지정 주석으로 확장 할 수 있음)
  2. 앞서 Espen에서 언급 한 스프링 실행 리스너.

0

업데이트 : 아래 제안에 결함이있는 이유는 Cherry의 의견을 참조하십시오. (댓글이 작동하지 않는 이유에 대해 다른 사람들에게 유용한 정보를 제공 할 수 있으므로 삭제하는 대신 여기에 답변을 유지하고 있습니다.)


의존성 주입 (예 : Spring)을 사용하는 경우 고려해야 할 또 다른 옵션은 @PostConstruct. 이렇게하면 종속성 주입이 완료되며 생성자에서는 그렇지 않습니다.

@PostConstruct
public void init() {
    // One-time initialization...
}


7
Junit 테스트의 경우 매우 나쁜 솔루션입니다. Junit은 테스트 메소드를 실행할 때마다 테스트 클래스 인스턴스를 생성합니다. 따라서 클래스에 6 개의 테스트 메서드가 있으면 클래스 생성자 @Before@After메서드가 6 번 호출됩니다! 따라서이 컨텍스트에서 주석 @PostConstruct처럼 작동 @Before합니다. 간단히 테스트 할 수 있습니다. 테스트 클래스에 2 개의 테스트 메서드를 넣고 @PostConstruct public void init() {System.out.println("started");}몇 번이나 인쇄되는지 로그에 추가 하고 확인합니다.
Cherry

정보를 위해 방금 JUnit 이 각 @Test실행에 대한 인스턴스를 생성하는 것에 대한 위의 주석에 설명 된 내용을 확인 하는 JUnit 문서 를 보았습니다 . "메서드를 실행하기 위해 JUnit은 먼저 클래스의 새 인스턴스를 생성 한 다음 주석이 달린 메소드를 호출합니다."
Steve Chambers

-2

그냥 사용하십시오 @BeforeClass:

@BeforeClass
public static void init() {
}

init각 테스트가 별도의 인스턴스에서 실행되기 때문에 비정 적인 것은 의미가 없습니다 . 인스턴스 init에서 실행되는 모든 시험의 인스턴스와 일치하지 않습니다.

비정 적이기를 원하는 유일한 이유는 하위 클래스에서 재정의하는 것이지만 정적 메서드로도이 작업을 수행 할 수 있습니다. 같은 이름을 사용하면 하위 클래스 init메서드 만 호출됩니다.


2
이 모든 질문은 비 정적 방식으로 수행 할 수있는 가능성에 관한 것입니다. 클래스에 인스턴스 변수가 필요한 경우 필요합니다.
Simon Forsberg

@SimonForsberg 예, 질문이 XY 문제라고 말하고 있습니다. op는 문제가 자식 클래스의 동작을 재정의한다고 말했습니다. 예제에 인스턴스 변수가 필요한 경우 다른 것을 제안 할 수 있습니다.
fgb


@SimonForsberg 그게 제가 말한 코멘트입니다. 어때요?
fgb
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.