To create the environment just once and to avoid inheritance I have defined a JUnit Suite class with a @ClassRule
:
@RunWith(Suite.class)
@Suite.SuiteClasses({
SuiteTest1.class
})
public class JUnitTest {
@ClassRule
private static DockerComposeContainer env = ...
@BeforeClass
public static void init(){
...
}
...
}
And there's a Test class that uses env in a test method:
public class SuiteTest1 {
@Test
public void method(){
client.query(...);// Executes a query against docker container
}
}
When I execute the tests by running the Test Suite everything works as expected. But when I directly try to run (even with IDE) the SuiteTest1
test class, it fails and nothing from the Suite is called (i.e. @
ClassRule and @BeforeClass
).
Any suggestions on how to achieve also the SuiteTest1 single execution in an good way (without calling static methods of JUnitTest
from within the SuiteTest1
) ?
Rephrasing the question: you want a JUnit suite with before-all and after-all hooks, which would also run when running the tests one by one (e.g. from an IDE).
AFAIK JUnit 4 provides nothing out-of-the-box for this, but if you're OK with incorporating some Spring third-parties deps (spring-test and spring-context) into your project I can propose a workaround I've been using.
The full example of what is described in this question can be found here.
Solution (using Spring)
We'll use Spring context for implementing our initialization and cleanup. Let's add a base class for our tests:
Note the
SpringClassRule
andSpringMethodRule
JUnit rules which enhance our base class with Spring-superpowers (Spring test annotation processing -ContextConfiguration
in this case, but there are many more goodies in there - see Spring testing reference for details). You could useSpringRunner
for this purpose, but it's a far less flexible solution (thus omitted).Test classes:
And the test suite:
Output when running the suite (removed Spring-specific logs for brievity):
Output when running a single test (
TestClass1
):A word of explanation
The way this works is because of Spring's context caching. Quote from the docs:
Beware that you will get another context (and another initialization) if you override the context configuration (e.g. add another context initializer with
ContextConfiguration
) for any of the classes in the hierarchy (TestClass1
orTestClass2
in our example).Using beans to share instances
You can define beans in your context. They'll be shared across all tests using the same context. This can be useful for sharing an object across the test suite (a Testcontainers container in your case judging by the tags).
Let's add a bean:
And inject it into the test classes:
ADockerContainer
class:(Example) output: