SetUp / tearDown (@ Before / @ After), why do we need them in JUnit?

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

We also know that Junit will create one instance of Test for each test method .

My question is, can we just move the contents of the setUp method to the Constructor class and delete the setUp method? Is there any specific reason to save the setUp method?

+50
java junit junit4 junit3
Sep 06 2018-10-10T00:
source share
6 answers

This (old) JUnit best practices reads as follows:

Do not use the test case constructor to configure the test case.

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

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

Imagine that when you configure, the configuration code throws an IllegalStateException . In response, Unit 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 uninformative; this only indicates that the test case cannot be instantiated. It does not detail the original location of the error or the place of origin. This lack of information makes it difficult to deduce the exception of the main reason.

Instead of setting the data in the constructor, perform a test setup overriding setUp() . Any exception thrown within setUp() correct. Compare the 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 where. This greatly simplifies the explanation of test setup failure.

+54
Sep 06 '10 at 2:50
source share

At work, we found something quite interesting that answers your question. When you run a test suite, especially a large test suite (200+), JUnit begins to use a lot of memory, this is due to the fact that ALL tests are installed before running any actual testing method.

We encountered a โ€œmemory leakโ€ because of this because we used Spring to connect some JPA EntiryManager objects for our database tests, this became a large number of objects and a large amount of memory, and about half of the testing path we received OutOfMemory exceptions.

IMHO, it is best to use setUp and tearDown to inject your dependencies and nullify any references to all classes, this will make your tests run faster and save you a lot of headache!

I hope you learn from our mistakes :)

+23
Sep 06 2018-10-06T00:
source share

Here are 3 good reasons. In short:

  • Some situations may prefer to delay setting up test instruments for as long as possible before the test script runs.

  • Some test cases may be part of the deep testing inheritance hierarchy. It may be preferable to postpone the installation of test fixtures until the completion of the full hierarchy of designers.

  • You will get better diagnostics if the installation code fails with setUp (), and not if the constructor fails.

1. Postpone instrument setup until testing

Design for usability http://www.artima.com/weblogs/viewpost.jsp?thread=70189

... And, as Elliott Rusty Harold put it, if you are going to create a new instance of TestCase for each test method, "why the hell with the setUp () method?" You can simply use the TestCase constructor.

I heard Bruce Eckel notice that there is one subtle difference between creating your device in setUp () and creating it in the TestCase constructor. JUnit creates all TestCase instances in front, and then calls setup (), the test method, and tearDown () for each instance. In other words, the subtle difference is that all constructors are called in the batch view from the front, while the setUp () method is called immediately before each test method . But this, apparently, is not so useful as in practice.

2. Postpone instrument setup until all test cases are created.

ETutorial Java Extreme Programming - 4.6 Tuning and Stalling

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

You might be wondering why you should write the setUp () method instead of simply initializing the fields in the test case constructor. In the end, since a new instance of the test case is created for each of its test methods, the constructor is always called before setUp (). In the 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 can defer initialization of the object until the instances of the derived [test] classes are completely built . This is a good technical reason why you can use setUp () instead of the constructor to initialize. Using setUp () and tearDown () is also useful for documentation purposes, simply because it can make it easier to read code .

3. Improved diagnostics in case of installation failure

Best practices of JUnit (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 the code where the configuration is performed in the test case constructor] that the installation code throws an IllegalStateException when performing the configuration. In response, JUnit will throw an AssertionFailedError, indicating that the test case cannot be created ....

This stack trace [of the exception created in the installation code in the test case constructor] turns out to be rather uninformative; this only indicates that the test case cannot be created.

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

This stack trace [of the exception created in the setUp () method instead of the test case constructor] is much more informative; it shows which exception was thrown (IllegalStateException) and where it came from. This greatly facilitates the explanation of test setup failure.

+22
06 Sep '10 at 4:01
source share

A custom runner, such as SpringJUnit4ClassRunner , may need to execute some code between the constructor and @Before . In this case, the runner may introduce some dependency that needs @Before methods. But dependency injection can only be started after the object is created.

+6
Sep 06 2018-10-06T00:
source share

The reason you need it is because for many tests, you often need to initialize the state before each test so that the tests can make assumptions about the startup state in which they work.

Suppose your test class wraps, say, database access. After each test, you want to delete all the changes made by your tests in db - if you did not, each test is performed against a slightly modified database. In addition, any given test may see a different set of changes if some subsets of previous tests failed. For example, suppose test1 inserts, test2 checks that you are reading the size of the table exactly. Day 1, test1 fails, and 0 is correct. Day 2, test1 succeeds, and 1 correct?

BTW, junit also supports @BeforeClass if you want to perform global configuration, and configuration and disabling are optional.

+3
Sep 06 '10 at 2:36
source share

I think some reason should like:

  • If you move the contents of @Before to the constructor, that's fine, but the contents of @After, where can you go?
  • The differences between the constructor and @ Before / @ After are that the constructor should be used for an instance of some for the class, @ Before / @ After is intended to prepare the resources of the test case.
-four
Sep 18 2018-10-18T00:
source share



All Articles