146

I have an Integration Test Suite. I have a IntegrationTestBase class for all my tests to extend. This base class has a @Before (public void setUp()) and @After (public void tearDown()) method to establish API and DB connections. What I've been doing is just overriding those two methods in each testcase and calling super.setUp() and super.tearDown(). However this can cause problems if someone forgets to call the super or puts them at the wrong place and an exception is thrown and they forget to call super in the finally or something.

What I want to do is make the setUp and tearDown methods on the base class final and then just add our own annotated @Before and @After methods. Doing some initial tests it appears to always call in this order:

Base @Before
Test @Before
Test
Test @After
Base @After

but I'm just a little concerned that the order isn't guaranteed and that it could cause problems. I looked around and haven't seen anything on the subject. Does anyone know if I can do that and not have any problems?

Code:

public class IntegrationTestBase {

    @Before
    public final void setUp() { *always called 1st?* }

    @After
    public final void tearDown() { *always called last?* }
}


public class MyTest extends IntegrationTestBase {

    @Before
    public final void before() { *always called 2nd?* }

    @Test
    public void test() { *always called 3rd?* }

    @After
    public final void after() { *always called 4th?* }
}
double-beep
  • 5,031
  • 17
  • 33
  • 41
Joel
  • 16,474
  • 17
  • 72
  • 93

6 Answers6

152

Yes, this behaviour is guaranteed:

@Before:

The @Before methods of superclasses will be run before those of the current class, unless they are overridden in the current class. No other ordering is defined.

@After:

The @After methods declared in superclasses will be run after those of the current class, unless they are overridden in the current class.

Soroush
  • 1,055
  • 2
  • 18
  • 26
axtavt
  • 239,438
  • 41
  • 511
  • 482
  • 21
    To be clear, the order-of-execution of all the `@Before` methods is not guaranteed. If there are 10 `@Before` methods, each of them can be executed in any order; just before any other method. – Swati May 20 '11 at 19:30
  • 8
    So instead of quoting the somewhat ambiguous documentation, can you please explain it in your own words? Are `@Before` and `@After` methods run before *every* other class method (once per method), or just before and after the entire suite of class methods (once per class) ? – B T Sep 13 '13 at 16:43
  • 8
    See the important catch stated by John Q Citizen: "this only applies if each method marked with @Before has a unique name in the class hierarchy" Very important to remember! – Bruno Bossola Aug 19 '14 at 13:33
  • I had a name conflict using the same method name on a @Before(d) method in a class and another method in its super class, on `junit-4.12`. – Stephane Jan 08 '17 at 14:13
  • Does this rule also apply to @BeforeExample methods of ConcordionRunner? – Adrian Pronk Jun 27 '18 at 21:19
  • According to invokeMethods in [FixtureInstance.java](https://github.com/concordion/concordion/blob/master/src/main/java/org/concordion/internal/FixtureInstance.java) it looks like parent-class methods are called before sub-class methods for both `@BeforeExample` and `@AfterExample` (and all the other Concordion annotated methods) – Adrian Pronk Jun 27 '18 at 21:30
58

One potential gotcha that has bitten me before:

I like to have at most one @Before method in each test class, because order of running the @Before methods defined within a class is not guaranteed. Typically, I will call such a method setUpTest().

But, although @Before is documented as The @Before methods of superclasses will be run before those of the current class. No other ordering is defined., this only applies if each method marked with @Before has a unique name in the class hierarchy.

For example, I had the following:

public class AbstractFooTest {
  @Before
  public void setUpTest() { 
     ... 
  }
}

public void FooTest extends AbstractFooTest {
  @Before
  public void setUpTest() { 
    ...
  }
}

I expected AbstractFooTest.setUpTest() to run before FooTest.setUpTest(), but only FooTest.setupTest() was executed. AbstractFooTest.setUpTest() was not called at all.

The code must be modified as follows to work:

public void FooTest extends AbstractFooTest {
  @Before
  public void setUpTest() {
    super.setUpTest();
    ...
  }
}
John Q Citizen
  • 3,138
  • 4
  • 26
  • 31
  • 1
    Why not just change the name of the @Before method in the base class? This will save you from having to call to super in all the children...anyway good catch with the same names issue – Lawrence Tierney Nov 19 '14 at 10:17
  • 31
    Just a remark to make things more secure: To avoid name clashes you can make the `@Before`/`@After` method(s) in the base class `final`, so the compiler will complain if you (accidentally) try to override them in the subclass. – Stefan Winkler Sep 09 '15 at 10:23
  • 6
    The parent method of the same name not being run does not sound like a JUnit behavior. That sounds like how basic over-riding works in OOP. The parent method basically does not exist at run time. The child replaces it for all intents and purposes. That is how Java works. – Brandon Aug 03 '16 at 20:51
  • 1
    Another gotcha is that the parent classes have to be public, otherwise their `@Before` marked methods will be ignored if a subclass also has a `@Before` method. – rusins Jul 29 '19 at 14:28
  • This is now documented behavior. "methods of superclasses will be run before those of the current class, *unless they are overridden in the current class*. No other ordering is defined" This allows having `@Before` mixin interfaces, but also preventing them from execution if an Override is given – iwat0qs Sep 02 '20 at 18:23
26

I think based on the documentation of the @Before and @After the right conclusion is to give the methods unique names. I use the following pattern in my tests:

public abstract class AbstractBaseTest {

  @Before
  public final void baseSetUp() { // or any other meaningful name
    System.out.println("AbstractBaseTest.setUp");
  }

  @After
  public final void baseTearDown() { // or any other meaningful name
    System.out.println("AbstractBaseTest.tearDown");
  }
}

and

public class Test extends AbstractBaseTest {

  @Before
  public void setUp() {
    System.out.println("Test.setUp");
  }

  @After
  public void tearDown() {
    System.out.println("Test.tearDown");
  }

  @Test
  public void test1() throws Exception {
    System.out.println("test1");
  }

  @Test
  public void test2() throws Exception {
    System.out.println("test2");
  }
}

give as a result

AbstractBaseTest.setUp
Test.setUp
test1
Test.tearDown
AbstractBaseTest.tearDown
AbstractBaseTest.setUp
Test.setUp
test2
Test.tearDown
AbstractBaseTest.tearDown

Advantage of this approach: Users of the AbstractBaseTest class cannot override the setUp/tearDown methods by accident. If they want to, they need to know the exact name and can do it.

(Minor) disadvantage of this approach: Users cannot see that there are things happening before or after their setUp/tearDown. They need to know that these things are provided by the abstract class. But I assume that's the reason why they use the abstract class

Maicon Mauricio
  • 2,052
  • 1
  • 13
  • 29
Matthias Hoefel
  • 325
  • 3
  • 6
  • 2
    nice example - would be even more illustrative if you had two @Test methods, so it can be seen that setUp and tearDown wrap *each* test method. – Mark Nov 11 '15 at 13:31
  • I think this is the basis for the best answer to the OP, but you should fill in your answer to standalone. Could you augment your example to cover the alternatives others have suggested, as well, and explain why your proposal is superior? – wachr Aug 18 '17 at 18:57
2

This isn't an answer to the tagline question, but it is an answer to the problems mentioned in the body of the question. Instead of using @Before or @After, look into using @org.junit.Rule because it gives you more flexibility. ExternalResource (as of 4.7) is the rule you will be most interested in if you are managing connections. Also, If you want guaranteed execution order of your rules use a RuleChain (as of 4.10). I believe all of these were available when this question was asked. Code example below is copied from ExternalResource's javadocs.

 public static class UsesExternalResource {
  Server myServer= new Server();

  @Rule
  public ExternalResource resource= new ExternalResource() {
      @Override
      protected void before() throws Throwable {
          myServer.connect();
         };

      @Override
      protected void after() {
          myServer.disconnect();
         };
     };

  @Test
  public void testFoo() {
      new Client().run(myServer);
     }
 }
successhawk
  • 3,071
  • 3
  • 28
  • 44
2

If you turn things around, you can declare your base class abstract, and have descendants declare setUp and tearDown methods (without annotations) that are called in the base class' annotated setUp and tearDown methods.

Buhb
  • 7,088
  • 3
  • 24
  • 38
  • 1
    not a bad idea, but I don't want to enforce a contract on the tests that don't need their own setUp/tearDown – Joel May 20 '11 at 19:31
2

You can use @BeforeClass annotation to assure that setup() is always called first. Similarly, you can use @AfterClass annotation to assure that tearDown() is always called last.

This is usually not recommended, but it is supported.

It's not exactly what you want - but it'll essentially keep your DB connection open the entire time your tests are running, and then close it once and for all at the end.

Swati
  • 50,291
  • 4
  • 36
  • 53
  • 2
    Actually, if you were to do this, I'd recommend creating a method `setupDB()` and `closeDB()` and marking them with `@BeforeClass` and `@AfterClass` and replacing your before/after methods with `setup()` and `tearDown()` – Swati May 20 '11 at 19:29
  • Methods annotated with `@BeforeClass` and `@AfterClass` need to be static. What about the case, when we want to use instance variables inside these methods? – Pratik Singhal Apr 02 '18 at 08:19
  • A warning when using `@BeforeClass` with Powermock: it only works for the first test run. See this issue: https://github.com/powermock/powermock/issues/398 – Dagmar Jun 21 '18 at 12:47