Reputation: 39437
I was trying to find a way to properly implement set up and tear down methods of a test class (for use with JUnit 4).
After trying lots of things and after some reseach I came across this.
Difference between setUp() and setUpBeforeClass()
So... if that's true... I find this design very inflexible.
I mean... In my case I want to run a @BeforeClass method once for the whole test class i.e. once before all test case methods, but after the initialization of my test class instance. And I need this method to be an instance method.
Seems I cannot do it. It is asking me to define the @BeforeClass method as static.
And if I try to use a @Before instance method, I can see that it is called many times... before each test case method. But I need it called just once.
Is there any decent way to do what I want? I am amazed...
Here is the interesting part: for @Before OK... I can do some workaround, I can define some boolean flag and just detect that the current call is the very first @Before method call. And only then do something useful/actual it in.
But for @After I want to detect the very last call of the @After method (so that I actually do something in it only if that's the very last call). But I cannot detect this last call with any flag.
I wonder how the designers of this JUnit thing didn't think of all that.
Or... am I missing something?
Upvotes: 0
Views: 641
Reputation: 1159
You can do all of that with JUnit5 (Jupiter JUnit that is). If you really need to use JUnit4 you may want to do something like this:
package com.jesperancinha.unittests;
import junit.extensions.TestSetup;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
public class OneTimeSetupUnitTest extends TestCase {
private static int up = 0;
private static int down = 0;
public static Test suite() {
return new TestSetup(new TestSuite(OneTimeSetupUnitTest.class)) {
protected void setUp() {
System.out.println("testStart");
up++;
System.out.println(up);
}
protected void tearDown() {
System.out.println("testEnd");
down++;
System.out.println(down);
}
};
}
@org.junit.Test
public void test1() {
System.out.println("test1");
System.out.println(up);
System.out.println(down);
}
@org.junit.Test
public void test2() {
System.out.println("test2");
System.out.println(up);
System.out.println(down);
}
}
The good thing about this is that you'd be doing nothing unexpected including for you scenario.
If you run this code snipet you should get something like:
I've placed flags so that I can show you some tracing to exactly explain what's going on. As you can see flag 'up' gets immediately updated upon the start of the unit tests. It doesn't change for the individual tests. Flag 'down' stays with value 0 until the end of the tests. Only at the end this flag is updated. This means that setUp has been called only once and tearDown also only once. You don't need to have both methods, so I think this is what you are looking for.
Upvotes: 1
Reputation: 44932
JUnit 4 requires @BeforeClass
and @AfterClass
to be present only on static
methods. If you can't make your method static
the easiest way to imitate it is to use a static holder with @After
:
private static MyTest lastTest;
public cleanup() {
// actual instance cleanup
}
@After
public tearDown() {
lastTest = this;
}
@AfterClass
public static cleanup() {
if (lastTest != null) {
lastTest.cleanup();
}
}
It's an ugly hack that might not work in certain situations and might break the interaction with custom runners e.g. SpringRunner
. It might work in simple scenarios.
To answer why neither JUnit 4 nor JUnit 5 doesn't support non-static methods for this use-case see this comment:
Without "test instance per test class" semantics it is required that @BeforeAll and @AfterAll methods be static. See the description of #48 for details.
However, once #48 is resolved, the static restriction will possibly be removed for scenarios in which that makes sense.
Upvotes: 0