In a unit test, I need to perform a quite complex setup (this may be a code smell but this is not what this question is about :-)). What I'm interested in is if it is better to have multiple @Before
methods performing the setup or just one, which calls helper methods to perform the initialization.
E.g.
@Before
public void setUpClientStub() {
}
@Before
public void setUpObjectUnderTest() {
}
vs.
@Before
public void setUp() {
setUpClientStub();
setUpObjectUnderTest();
}
As has been said in other responses, the order in which JUnit finds methods is not guaranteed, so the execution order of @Before
methods can't be guaranteed. The same is true of @Rule
, it suffers from the same lack of guarantee. If this will always be the same code, then there isn't any point in splitting into two methods.
If you do have two methods, and more importantly, if you wish to use them from multiple places, then you can combine rules using a RuleChain, which was introduced in 4.10. This allows the specific ordering of rules, such as:
public static class UseRuleChain {
@Rule
public TestRule chain= RuleChain
.outerRule(new LoggingRule("outer rule"))
.around(new LoggingRule("middle rule"))
.around(new LoggingRule("inner rule"));
@Test
public void example() {
assertTrue(true);
}
}
This produces:
starting outer rule
starting middle rule
starting inner rule
finished inner rule
finished middle rule
finished outer rule
So you can either upgrade to 4.10 or just steal the class.
In your case, you could define two rules, one for client setup and one for object, and combine them in a RuleChain
. Using ExternalResource.
public static class UsesExternalResource {
private TestRule clientRule = new ExternalResource() {
@Override
protected void before() throws Throwable {
setupClientCode();
};
@Override
protected void after() {
tearDownClientCode()
};
};
@Rule public TestRule chain = RuleChain
.outerRule(clientRule)
.around(objectRule);
}
So you'll have the following execution order:
clientRule.before()
objectRule.before()
the test
objectRule.after()
clientRule.after()
I would do the latter. AFAIK, there is no way to guarantee order of @Before annotated setup methods.
Note that there are no guarantees about the order in which @Before
annotated methods are invoked. If there are some dependencies between them (e.g. one method must be called before the other), you must use the latter form.
Otherwise this is a matter of preference, just keep them in a single place so it is easy to spot them.
I don't think it makes much of a difference, but I personally prefer the second one (the order Before methods are executed being not defined, you'll have a better control that way).
For me it seems using JUnit 4.12
, the methods annotated with @Before
get indeed sorted deterministically by the following characteristic:
by reversed lexicographic order with respect to the method name.
You can see this behaviour by executing this Testclass:
import java.util.Arrays;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
/*
* key points:
* - multiple @Before methods get sorted by reversed lexicographic order
* */
public class JUnitLifecyle {
@BeforeClass
public static void runsOnceBeforeClassIsInited() {
System.out.println("@BeforeClass");
}
public JUnitLifecyle() {
System.out.println("Constructor");
}
@Before
public void a() {
System.out.println("@Before a");
}
@Before
public void b() {
System.out.println("@Before b");
}
@Before
public void cd() {
System.out.println("@Before cd");
}
@Before
public void ca() {
System.out.println("@Before ca");
}
@Before
public void cc() {
System.out.println("@Before cc");
}
@Before
public void d() {
System.out.println("@Before d");
}
@Before
public void e() {
System.out.println("@Before e");
}
@Test
public void firstTest() {
System.out.println("@Test 1");
}
@Test
public void secondTest() {
System.out.println("@Test 2");
}
@After
public void runsAfterEveryTestMethod() {
System.out.println("@After");
}
@AfterClass
public static void runsOnceAfterClass() {
System.out.println("@AfterClass");
}
}
I came to this conclusion after playing around with the output, while changing the method names of the methods annotated with @Before
.
Keeping this reversed lexicographic order in mind you could name your methods accordingly to let JUnit
execute your setup tasks in the right order.
Although the above approach is possible, I think you should not do this in your tests, because the Java-Annotations thing in JUnit was introduced to get away from convention-based testing.