program tip

setUp / tearDown (@ Before / @ After) 왜 JUnit에서 필요한가요?

radiobox 2020. 12. 1. 07:52
반응형

setUp / tearDown (@ Before / @ After) 왜 JUnit에서 필요한가요?


setUp (@Before)이 테스트 메서드보다 먼저 실행되고 tearDown (@After)이 테스트 메서드 후에 실행된다는 것을 모두 알고 있다고 생각합니다.

또한 Junit이 테스트 방법 당 하나의 Test 인스턴스를 생성한다는 것을 알고 있습니다 .

내 질문은 setUp 메서드 내용을 생성자 클래스로 이동하고 setUp 메서드를 제거 할 수 있다는 것입니다. setUp 메소드를 유지해야하는 특별한 이유가 있습니까?


이 (이전) JUnit 모범 사례 기사는 다음과 같이 설명합니다.

테스트 케이스를 설정하기 위해 테스트 케이스 생성자를 사용하지 마십시오.

생성자에서 테스트 케이스를 설정하는 것은 좋은 생각이 아닙니다. 중히 여기다:

public class SomeTest extends TestCase
   public SomeTest (String testName) {
      super (testName);
      // Perform test set-up
   }
}

설정을 수행하는 동안 설정 코드가 IllegalStateException. 이에 대한 응답으로 JUnit은 AssertionFailedError테스트 케이스를 인스턴스화 할 수 없음을 나타내는를 throw합니다 . 다음은 결과 스택 추적의 예입니다.

junit.framework.AssertionFailedError: Cannot instantiate test case: test1   
    at junit.framework.Assert.fail(Assert.java:143)
    at junit.framework.TestSuite.runTest(TestSuite.java:178)
    at junit.framework.TestCase.runBare(TestCase.java:129)
    at junit.framework.TestResult.protect(TestResult.java:100)
    at junit.framework.TestResult.runProtected(TestResult.java:117)
    at junit.framework.TestResult.run(TestResult.java:103)
    at junit.framework.TestCase.run(TestCase.java:120)
    at junit.framework.TestSuite.run(TestSuite.java, Compiled Code)
    at junit.ui.TestRunner2.run(TestRunner.java:429)

이 스택 추적은 다소 정보가 없음을 증명합니다. 테스트 케이스를 인스턴스화 할 수 없음을 나타냅니다. 원래 오류의 위치 또는 출처를 자세히 설명하지 않습니다. 이러한 정보 부족은 예외의 근본 원인을 추론하기 어렵게 만듭니다.

생성자에서 데이터를 설정하는 대신을 재정 의하여 테스트 설정을 수행 setUp()합니다. 내에서 발생한 모든 예외 setUp()가 올바르게보고됩니다. 이 스택 추적을 이전 예제와 비교하십시오.

java.lang.IllegalStateException: Oops
    at bp.DTC.setUp(DTC.java:34) 
    at junit.framework.TestCase.runBare(TestCase.java:127)
    at junit.framework.TestResult.protect(TestResult.java:100)
    at junit.framework.TestResult.runProtected(TestResult.java:117)
    at junit.framework.TestResult.run(TestResult.java:103)
    ...

이 스택 추적은 훨씬 더 많은 정보를 제공합니다. 어떤 예외가 발생했는지 ( IllegalStateException) 어디에서 발생했는지 보여줍니다 . 그러면 테스트 설정의 실패를 훨씬 쉽게 설명 할 수 있습니다.


직장에서 우리는 귀하의 질문에 답하는 다소 흥미로운 것을 발견했습니다. 테스트 스위트, 특히 대규모 테스트 세트 (200+)를 실행하면 JUnit이 많은 메모리를 사용하기 시작합니다. 이는 실제 테스트 메소드가 실행되기 전에 모든 테스트가 인스턴스화되기 때문입니다.

데이터베이스 테스트를 위해 일부 JPA EntiryManager 객체를 연결하기 위해 Spring을 사용했기 때문에 "메모리 누수"가 발생했습니다. 이것은 많은 객체와 많은 메모리가되었고 테스트를 통해 OutOfMemory 예외가 발생하는 절반 정도가되었습니다. .

IMHO, 모범 사례는 setUp 및 tearDown을 사용하여 종속성을 주입하고 모든 클래스 참조를 null로 지정하는 것입니다. 이렇게하면 테스트가 더 빠르게 실행되고 많은 두통을 줄일 수 있습니다!

우리의 실수에서 배우 길 바랍니다 :)


그 이유는 3 가지입니다. 요약해서 말하자면:

  1. 어떤 상황 에서는 테스트 케이스가 실행 되기 직전에 가능한 한 테스트 픽스처 설정을 연기하는 것을 선호 할 수 있습니다 .

  2. 일부 테스트 케이스는 깊은 테스트 케이스 상속 계층의 일부일 수 있습니다. 생성자의 전체 계층 구조가 완료 될 때까지 테스트 픽스처 설정을 연기하는 것이 좋습니다.

  3. 설정 코드가 생성자에서 실패하는 것보다 setUp ()에서 실패하면 더 나은 진단을 얻을 수 있습니다.

1. 테스트 케이스 직전까지 픽스처 설정 연기

유용성을위한 디자인
http://www.artima.com/weblogs/viewpost.jsp?thread=70189

... And as Elliotte Rusty Harold put it, if you're going to create a new TestCase instance for each test method, "why the hell bother with a setUp() method?" You can just use the TestCase constructor.

I've heard Bruce Eckel point out that there is one subtle difference between creating your fixture in setUp() versus creating it in the TestCase constructor. JUnit creates all the TestCase instances up front, and then for each instance, calls setup(), the test method, and tearDown(). In other words, the subtle difference is that constructors are all invoked in batch up front, whereas the setUp() method is called right before each test method. But this seems to be not that useful a difference in practice.

2. Defer setting up fixtures until after all test cases are instantiated

ETutorial's Java Extreme Programming - 4.6 Set Up and Tear Down
http://etutorials.org/Programming/Java+extreme+programming/Chapter+4.+JUnit/4.6+Set+Up+and+Tear+Down/

You may be wondering why you should write a setUp( ) method instead of simply initializing fields in a test case's constructor. After all, since a new instance of the test case is created for each of its test methods, the constructor is always called before setUp( ). In a vast majority of cases, you can use the constructor instead of setUp( ) without any side effects.

In cases where your test case is part of a deeper inheritance hierarchy, you may wish to postpone object initialization until instances of derived [test] classes are fully constructed. This is a good technical reason why you might want to use setUp( ) instead of a constructor for initialization. Using setUp( ) and tearDown( ) is also good for documentation purposes, simply because it may make the code easier to read.

3. Better diagnostics in case of setup failure

JUnit best practices (JavaWorld)
http://www.javaworld.com/jw-12-2000/jw-1221-junit.html

Setting up a test case in the constructor is not a good idea. ...

Imagine [in code where setup is done in the test case constructor] that while performing the setup, the setup code throws an IllegalStateException. In response, JUnit would throw an AssertionFailedError, indicating that the test case could not be instantiated. ...

This stack trace [of an exception thrown in setup code in the test case constructor] proves rather uninformative; it only indicates that the test case could not be instantiated.

Instead of setting up the data in the constructor, perform test setup by overriding setUp(). Any exception thrown within setUp() is reported correctly. ...

This stack trace [of an exception thrown in setUp() method instead of the test case constructor] is much more informative; it shows which exception was thrown (IllegalStateException) and from where. That makes it far easier to explain the test setup's failure.


A custom runner such as SpringJUnit4ClassRunner may need to run some codes between the constructor and @Before method. In this case, the runner may inject some dependency which the @Before methods needs. But dependency injection can only be run after the object is constructed.


The reason you need this is that for many tests you often need to initialize state before each test so that the tests can all make assumptions about the start state they're running in.

Suppose your test class wraps, say database access. After each test you'd want to remove whatever changes your tests have made to the db - if you didn't do that, each test runs against a slightly modified database. Additionally, any given test may see a different set of changes if some subset of the previous tests have failed. For example, suppose test1 does an insert, test2 checks that you're accurately reading the table size. Day 1, test1 fails, and 0 is correct. Day 2, test1 succeeds, and 1 is correct?

BTW, junit also supports @BeforeClass if you want to do a global setup, and setup and teardowns are optional.


I think some reason should like the following:

  1. If you move @Before contents to Constructor, That's fine, but the @After contents where you get to move?
  2. The differences of Constructor and @Before/@After is that Constructor should be used to instance some for class, @Before/@After is for preparing test case resources.

참고URL : https://stackoverflow.com/questions/3648712/setup-teardown-before-after-why-we-need-them-in-junit

반응형