The following sample test generates the output as printed below.
Sample test:
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
public class OuterTest extends ParentTest implements TestInterface1, TestInterface2
{
@BeforeEach
void outerSetup()
{
System.out.println( " outerSetup" );
}
@AfterEach
void outerTearDown()
{
System.out.println( " outerTearDown" );
}
@Test
void outerTest1()
{
System.out.println( " outerTest1" );
}
@Test
void outerTest2()
{
System.out.println( " outerTest2" );
}
@Nested
class InnerTest
{
@BeforeEach
void innerSetup()
{
System.out.println( " innerSetup" );
}
@AfterEach
void innerTearDown()
{
System.out.println( " innerTearDown" );
}
@Test
void innerTest1()
{
System.out.println( " innerTest1" );
}
@Test
void innerTest2()
{
System.out.println( " innerTest2" );
}
@RepeatedTest(3)
void innerRepeatedTest()
{
System.out.println( " innerRepeatedTest" );
}
@ParameterizedTest
@ValueSource(strings = { "foo", "bar", "baz" })
void innerParameterizedTest( final String input )
{
System.out.println( " innerParameterizedTest - " + input );
}
}
}
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
public class ParentTest
{
@BeforeEach
void parentSetup()
{
System.out.println( "parentSetup" );
}
@AfterEach
void parentTearDown()
{
System.out.println( "parentTearDown" );
}
}
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
public interface TestInterface1
{
@BeforeEach
default void interface1Setup()
{
System.out.println( "interface1Setup" );
}
@AfterEach
default void interface1TearDown()
{
System.out.println( "interface1TearDown" );
}
}
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
public interface TestInterface2
{
@BeforeEach
default void interface2Setup()
{
System.out.println( "interface2Setup" );
}
@AfterEach
default void interface2TearDown()
{
System.out.println( "interface2TearDown" );
}
}
Output:
parentSetup
interface1Setup
interface2Setup
outerSetup
outerTest1
outerTearDown
interface1TearDown
interface2TearDown
parentTearDown
parentSetup
interface1Setup
interface2Setup
outerSetup
outerTest2
outerTearDown
interface1TearDown
interface2TearDown
parentTearDown
parentSetup
interface1Setup
interface2Setup
outerSetup
innerSetup
innerRepeatedTest
innerTearDown
outerTearDown
interface1TearDown
interface2TearDown
parentTearDown
parentSetup
interface1Setup
interface2Setup
outerSetup
innerSetup
innerRepeatedTest
innerTearDown
outerTearDown
interface1TearDown
interface2TearDown
parentTearDown
parentSetup
interface1Setup
interface2Setup
outerSetup
innerSetup
innerRepeatedTest
innerTearDown
outerTearDown
interface1TearDown
interface2TearDown
parentTearDown
parentSetup
interface1Setup
interface2Setup
outerSetup
innerSetup
innerParameterizedTest - foo
innerTearDown
outerTearDown
interface1TearDown
interface2TearDown
parentTearDown
parentSetup
interface1Setup
interface2Setup
outerSetup
innerSetup
innerParameterizedTest - bar
innerTearDown
outerTearDown
interface1TearDown
interface2TearDown
parentTearDown
parentSetup
interface1Setup
interface2Setup
outerSetup
innerSetup
innerParameterizedTest - baz
innerTearDown
outerTearDown
interface1TearDown
interface2TearDown
parentTearDown
parentSetup
interface1Setup
interface2Setup
outerSetup
innerSetup
innerTest1
innerTearDown
outerTearDown
interface1TearDown
interface2TearDown
parentTearDown
parentSetup
interface1Setup
interface2Setup
outerSetup
innerSetup
innerTest2
innerTearDown
outerTearDown
interface1TearDown
interface2TearDown
parentTearDown
For our use case we want to achieve, that the @BeforeEach/@AfterEach methods are only called before/after each test in class OuterTest and before the first resp. after the last test in class InnerTest, but not between the tests of the inner class.
So the desired output is the following:
parentSetup
interface1Setup
interface2Setup
outerSetup
outerTest1
outerTearDown
interface1TearDown
interface2TearDown
parentTearDown
parentSetup
interface1Setup
interface2Setup
outerSetup
outerTest2
outerTearDown
interface1TearDown
interface2TearDown
parentTearDown
parentSetup
interface1Setup
interface2Setup
outerSetup
innerSetup
innerRepeatedTest
innerTearDown
innerSetup
innerRepeatedTest
innerTearDown
innerSetup
innerRepeatedTest
innerTearDown
innerSetup
innerParameterizedTest - foo
innerTearDown
innerSetup
innerParameterizedTest - bar
innerTearDown
innerSetup
innerParameterizedTest - baz
innerTearDown
innerSetup
innerTest1
innerTearDown
innerSetup
innerTest2
innerTearDown
outerTearDown
interface1TearDown
interface2TearDown
parentTearDown
I tried to change the behavior of the @BeforeEach/@AfterEach methods by implementing an extension, which implements an InvocationInterceptor, but I failed to find out if a test class is the last test in the inner class, which would enable to decide, if the @BeforeEach/@AfterEach methods of the outer class should be called or not.
Does anyone know how to achieve this?
Thanks in advance!
If you are able to extract your actual outer setup and teardown methods, you can introduce a second
@Nestedclass for the outer tests and use@BeforeAlland@AfterAllto invoke the outer setup/teardown once:Output (order of the nested class may vary on your system):
If you are on Java 16+, you can also omit
@TestInstance(TestInstance.Lifecycle.PER_CLASS)and usestaticinstead.