setUp/tearDown (@Before/@After) why we need them in JUnit?

JavaJunitJunit4Junit3

Java Problem Overview


I believe that we are all know that setUp (@Before) will execute before any test method and tearDown(@After) will execute after test method.

Also we know that Junit will create one instance of Test per test method.

my question is that can we just move setUp method content to class Constructor and remove setUp method? is there any specific reason to keep setUp method?

Java Solutions


Solution 1 - Java

This (old) JUnit best practices article puts it like this:

> ### Do not use the test-case constructor to set up a test case > > Setting up a test case in the > constructor is not a good idea. > Consider: > > public class SomeTest extends TestCase > public SomeTest (String testName) { > super (testName); > // Perform test set-up > } > } > > > > Imagine 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. Here is an example of > the resulting stack trace: > > 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) > > This stack trace proves rather > uninformative; it only indicates that > the test case could not be > instantiated. It doesn't detail the > original error's location or place of > origin. This lack of information makes > it hard to deduce the exception's > underlying cause. > > Instead of setting up the data in the > constructor, perform test setup by > overriding setUp(). Any exception > thrown within setUp() is reported > correctly. Compare this stack trace > with the previous example: > > 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) > ... > > This stack trace 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.

Solution 2 - Java

At work we've discovered something rather interesting which answers your question. When you run a test suite, especially a large set of tests (200+), JUnit starts to use a LOT of memory. This is because ALL the tests are instanced before any actual test method is run.

We ran into a "memory leak" because of this. Because we used Spring to wire in some JPA EntityManager objects for our database tests, this became A LOT of objects and a lot of memory, and about half way through the tests we were getting OutOfMemory exceptions.

IMHO, best practice is to use setUp and tearDown to inject your dependencies and null out any and all class references. This will make your tests run faster and save you a lot of headache!

Hope you learn from our mistakes :)

Solution 3 - Java

Here are 3 good reasons why. In summary:

  1. Some situations may prefer to defer setting up test fixtures as long as possible, to just before the test case executes.

  2. Some test cases may be part of a deep test case inheritance hierarchy. It may be preferable to defer setting up test fixtures until the full hierarchy of constructors has completed.

  3. You get better diagnostics if setup code fails in setUp() rather than if it fails in the constructor.

1. Defer setting up fixtures until just before test case

Design for Usability
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.

Solution 4 - Java

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.

Solution 5 - Java

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.

Solution 6 - Java

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmhshamsView Question on Stackoverflow
Solution 1 - JavaPascal ThiventView Answer on Stackoverflow
Solution 2 - JavaBjornSView Answer on Stackoverflow
Solution 3 - JavaBert FView Answer on Stackoverflow
Solution 4 - JavaRichNView Answer on Stackoverflow
Solution 5 - JavaSteve B.View Answer on Stackoverflow
Solution 6 - JavaGoingWellView Answer on Stackoverflow