diff --git a/docs/examples/junit4/generic/build.gradle b/docs/examples/junit4/generic/build.gradle deleted file mode 100644 index 60764dd7476..00000000000 --- a/docs/examples/junit4/generic/build.gradle +++ /dev/null @@ -1,12 +0,0 @@ -description = "Examples for docs" - -dependencies { - testImplementation "junit:junit:4.13.2" - testImplementation project(":testcontainers") - testImplementation project(":testcontainers-selenium") - testImplementation project(":testcontainers-mysql") - - testRuntimeOnly 'com.mysql:mysql-connector-j:8.2.0' - testImplementation "org.seleniumhq.selenium:selenium-api:4.35.0" - testImplementation 'org.assertj:assertj-core:3.27.4' -} diff --git a/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java b/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java deleted file mode 100644 index 82e3d83ab24..00000000000 --- a/docs/examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java +++ /dev/null @@ -1,110 +0,0 @@ -package org.testcontainers.containers.startupcheck; - -import lombok.SneakyThrows; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.containers.output.OutputFrame; -import org.testcontainers.containers.output.WaitingConsumer; -import org.testcontainers.utility.DockerImageName; - -import java.time.Duration; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import static org.assertj.core.api.Assertions.assertThat; - -@RunWith(Suite.class) -@Suite.SuiteClasses( - { - StartupCheckStrategyTest.OneShotStrategyTest.class, - StartupCheckStrategyTest.IndefiniteOneShotStrategyTest.class, - StartupCheckStrategyTest.MinimumDurationStrategyTest.class, - } -) -public class StartupCheckStrategyTest { - - private static final String HELLO_TESTCONTAINERS = "Hello Testcontainers!"; - - private static void waitForHello(GenericContainer container) throws TimeoutException { - WaitingConsumer consumer = new WaitingConsumer(); - container.followOutput(consumer, OutputFrame.OutputType.STDOUT); - - consumer.waitUntil(frame -> frame.getUtf8String().contains(HELLO_TESTCONTAINERS), 30, TimeUnit.SECONDS); - } - - public static class OneShotStrategyTest { - - @Rule - // spotless:off - // withOneShotStrategy { - public GenericContainer bboxWithOneShot = new GenericContainer<>(DockerImageName.parse("busybox:1.31.1")) - .withCommand(String.format("echo %s", HELLO_TESTCONTAINERS)) - .withStartupCheckStrategy( - new OneShotStartupCheckStrategy().withTimeout(Duration.ofSeconds(3)) - ); - - // } - // spotless:on - - @SneakyThrows - @Test - public void testCommandIsExecuted() { - waitForHello(bboxWithOneShot); - - assertThat(bboxWithOneShot.isRunning()).isFalse(); - } - } - - public static class IndefiniteOneShotStrategyTest { - - @Rule - // spotless:off - // withIndefiniteOneShotStrategy { - public GenericContainer bboxWithIndefiniteOneShot = new GenericContainer<>( - DockerImageName.parse("busybox:1.31.1") - ) - .withCommand("sh", "-c", String.format("sleep 5 && echo \"%s\"", HELLO_TESTCONTAINERS)) - .withStartupCheckStrategy( - new IndefiniteWaitOneShotStartupCheckStrategy() - ); - - // } - // spotless:on - - @SneakyThrows - @Test - public void testCommandIsExecuted() { - waitForHello(bboxWithIndefiniteOneShot); - - assertThat(bboxWithIndefiniteOneShot.isRunning()).isFalse(); - } - } - - public static class MinimumDurationStrategyTest { - - @Rule - // spotless:off - // withMinimumDurationStrategy { - public GenericContainer bboxWithMinimumDuration = new GenericContainer<>( - DockerImageName.parse("busybox:1.31.1") - ) - .withCommand("sh", "-c", String.format("sleep 5 && echo \"%s\"", HELLO_TESTCONTAINERS)) - .withStartupCheckStrategy( - new MinimumDurationRunningStartupCheckStrategy(Duration.ofSeconds(1)) - ); - - // } - // spotless:on - - @SneakyThrows - @Test - public void testCommandIsExecuted() { - assertThat(bboxWithMinimumDuration.isRunning()).isTrue(); - - waitForHello(bboxWithMinimumDuration); - } - } -} diff --git a/docs/examples/junit4/redis/build.gradle b/docs/examples/junit4/redis/build.gradle deleted file mode 100644 index 8af186d16bb..00000000000 --- a/docs/examples/junit4/redis/build.gradle +++ /dev/null @@ -1,9 +0,0 @@ -description = "Examples for docs" - -dependencies { - api "io.lettuce:lettuce-core:6.8.0.RELEASE" - - testImplementation "junit:junit:4.13.2" - testImplementation project(":testcontainers") - testImplementation 'org.assertj:assertj-core:3.27.4' -} diff --git a/docs/examples/junit4/redis/src/main/java/quickstart/RedisBackedCache.java b/docs/examples/junit4/redis/src/main/java/quickstart/RedisBackedCache.java deleted file mode 100644 index 1123858ca17..00000000000 --- a/docs/examples/junit4/redis/src/main/java/quickstart/RedisBackedCache.java +++ /dev/null @@ -1,22 +0,0 @@ -package quickstart; - -import io.lettuce.core.RedisClient; -import io.lettuce.core.api.StatefulRedisConnection; - -public class RedisBackedCache { - - private final StatefulRedisConnection connection; - - public RedisBackedCache(String hostname, Integer port) { - RedisClient client = RedisClient.create(String.format("redis://%s:%d/0", hostname, port)); - connection = client.connect(); - } - - public String get(String key) { - return connection.sync().get(key); - } - - public void put(String key, String value) { - connection.sync().set(key, value); - } -} diff --git a/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java b/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java deleted file mode 100644 index e4c4424315b..00000000000 --- a/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package quickstart; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.testcontainers.containers.GenericContainer; -import org.testcontainers.utility.DockerImageName; - -import static org.assertj.core.api.Assertions.assertThat; - -public class RedisBackedCacheIntTest { - - private RedisBackedCache underTest; - - // rule { - @Rule - public GenericContainer redis = new GenericContainer(DockerImageName.parse("redis:6-alpine")) - .withExposedPorts(6379); - - // } - - @Before - public void setUp() { - String address = redis.getHost(); - Integer port = redis.getFirstMappedPort(); - - // Now we have an address and port for Redis, no matter where it is running - underTest = new RedisBackedCache(address, port); - } - - @Test - public void testSimplePutAndGet() { - underTest.put("test", "example"); - - String retrieved = underTest.get("test"); - assertThat(retrieved).isEqualTo("example"); - } -} diff --git a/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java b/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java deleted file mode 100644 index e3f52403c48..00000000000 --- a/docs/examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java +++ /dev/null @@ -1,27 +0,0 @@ -package quickstart; - -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -@Ignore("This test class is deliberately invalid, as it relies on a non-existent local Redis") -public class RedisBackedCacheIntTestStep0 { - - private RedisBackedCache underTest; - - @Before - public void setUp() { - // Assume that we have Redis running locally? - underTest = new RedisBackedCache("localhost", 6379); - } - - @Test - public void testSimplePutAndGet() { - underTest.put("test", "example"); - - String retrieved = underTest.get("test"); - assertThat(retrieved).isEqualTo("example"); - } -} diff --git a/docs/examples/junit4/redis/src/test/resources/logback-test.xml b/docs/examples/junit4/redis/src/test/resources/logback-test.xml deleted file mode 100644 index 62bc2c43d3a..00000000000 --- a/docs/examples/junit4/redis/src/test/resources/logback-test.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - %d{HH:mm:ss.SSS} %-5level %logger - %msg%n - - - - - - - diff --git a/docs/examples/junit5/generic/build.gradle b/docs/examples/junit5/generic/build.gradle new file mode 100644 index 00000000000..61f73796c28 --- /dev/null +++ b/docs/examples/junit5/generic/build.gradle @@ -0,0 +1,24 @@ +description = "Examples for docs" + +buildDir = "$rootDir/build/docs-examples/junit5/generic" + +dependencies { + testImplementation project(":testcontainers") + testImplementation project(":testcontainers-junit-jupiter") + testImplementation project(":testcontainers-selenium") + testImplementation project(":testcontainers-mysql") + + testRuntimeOnly 'com.mysql:mysql-connector-j:8.2.0' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter:5.13.4' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.10.3' + testImplementation "org.seleniumhq.selenium:selenium-api:4.35.0" + testImplementation 'org.assertj:assertj-core:3.27.4' +} + +test { + useJUnitPlatform() + // Keep these generic snippets compile-checked without starting every referenced container in docs CI. + enabled = false +} + +check.dependsOn(testClasses) diff --git a/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java b/docs/examples/junit5/generic/src/test/java/generic/CmdModifierTest.java similarity index 79% rename from docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java rename to docs/examples/junit5/generic/src/test/java/generic/CmdModifierTest.java index 52c7f621d07..a5f6b4e0b74 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/CmdModifierTest.java +++ b/docs/examples/junit5/generic/src/test/java/generic/CmdModifierTest.java @@ -2,11 +2,11 @@ import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.model.Info; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.testcontainers.DockerClientFactory; -import org.testcontainers.containers.Container; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.utility.DockerImageName; import java.io.IOException; @@ -14,10 +14,11 @@ import static org.assertj.core.api.Assertions.assertThat; +@Testcontainers public class CmdModifierTest { // hostname { - @Rule + @Container public GenericContainer theCache = new GenericContainer<>(DockerImageName.parse("redis:6-alpine")) .withCreateContainerCmdModifier(cmd -> cmd.withHostName("the-cache")); @@ -29,7 +30,7 @@ public class CmdModifierTest { private long memorySwapInBytes = 64l * 1024l * 1024l; - @Rule + @Container public GenericContainer memoryLimitedRedis = new GenericContainer<>(DockerImageName.parse("redis:6-alpine")) .withCreateContainerCmdModifier(cmd -> { cmd.getHostConfig() @@ -42,13 +43,16 @@ public class CmdModifierTest { @Test public void testHostnameModified() throws IOException, InterruptedException { - final Container.ExecResult execResult = theCache.execInContainer("hostname"); + final org.testcontainers.containers.Container.ExecResult execResult = theCache.execInContainer("hostname"); assertThat(execResult.getStdout().trim()).isEqualTo("the-cache"); } @Test public void testMemoryLimitModified() throws IOException, InterruptedException { - final Container.ExecResult execResult = memoryLimitedRedis.execInContainer("cat", getMemoryLimitFilePath()); + final org.testcontainers.containers.Container.ExecResult execResult = memoryLimitedRedis.execInContainer( + "cat", + getMemoryLimitFilePath() + ); assertThat(execResult.getStdout().trim()).isEqualTo(String.valueOf(memoryInBytes)); } diff --git a/docs/examples/junit4/generic/src/test/java/generic/CommandsTest.java b/docs/examples/junit5/generic/src/test/java/generic/CommandsTest.java similarity index 78% rename from docs/examples/junit4/generic/src/test/java/generic/CommandsTest.java rename to docs/examples/junit5/generic/src/test/java/generic/CommandsTest.java index 5b4df0dbb66..da73931e376 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/CommandsTest.java +++ b/docs/examples/junit5/generic/src/test/java/generic/CommandsTest.java @@ -1,15 +1,17 @@ package generic; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.utility.DockerImageName; import static org.assertj.core.api.Assertions.assertThat; +@Testcontainers public class CommandsTest { - @Rule + @Container // startupCommand { public GenericContainer redisWithCustomPort = new GenericContainer(DockerImageName.parse("redis:6-alpine")) .withCommand("redis-server --port 7777") diff --git a/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java b/docs/examples/junit5/generic/src/test/java/generic/ContainerCreationTest.java similarity index 87% rename from docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java rename to docs/examples/junit5/generic/src/test/java/generic/ContainerCreationTest.java index e202580c247..9923a1e5125 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ContainerCreationTest.java +++ b/docs/examples/junit5/generic/src/test/java/generic/ContainerCreationTest.java @@ -1,19 +1,21 @@ package generic; -import org.junit.ClassRule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.utility.DockerImageName; import static org.assertj.core.api.Assertions.assertThat; +@Testcontainers public class ContainerCreationTest { // spotless:off // simple { public static final DockerImageName REDIS_IMAGE = DockerImageName.parse("redis:6-alpine"); - @ClassRule + @Container public static GenericContainer redis = new GenericContainer<>(REDIS_IMAGE) .withExposedPorts(6379); @@ -27,7 +29,7 @@ public class ContainerCreationTest { // Set up a plain OS container and customize environment, // command and exposed ports. This just listens on port 80 // and always returns '42' - @ClassRule + @Container public static GenericContainer alpine = new GenericContainer<>(ALPINE_IMAGE) .withExposedPorts(80) .withEnv("MAGIC_NUMBER", "42") diff --git a/docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java b/docs/examples/junit5/generic/src/test/java/generic/ContainerLabelTest.java similarity index 100% rename from docs/examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java rename to docs/examples/junit5/generic/src/test/java/generic/ContainerLabelTest.java diff --git a/docs/examples/junit4/generic/src/test/java/generic/DependsOnTest.java b/docs/examples/junit5/generic/src/test/java/generic/DependsOnTest.java similarity index 76% rename from docs/examples/junit4/generic/src/test/java/generic/DependsOnTest.java rename to docs/examples/junit5/generic/src/test/java/generic/DependsOnTest.java index c48d55899f0..5b60d619743 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/DependsOnTest.java +++ b/docs/examples/junit5/generic/src/test/java/generic/DependsOnTest.java @@ -1,18 +1,20 @@ package generic; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; import static org.assertj.core.api.Assertions.assertThat; +@Testcontainers public class DependsOnTest { - @Rule + @Container // dependsOn { public GenericContainer redis = new GenericContainer<>("redis:6-alpine").withExposedPorts(6379); - @Rule + @Container public GenericContainer nginx = new GenericContainer<>("nginx:1.27.0-alpine3.19-slim") .dependsOn(redis) .withExposedPorts(80); diff --git a/docs/examples/junit4/generic/src/test/java/generic/ExampleImageNameSubstitutor.java b/docs/examples/junit5/generic/src/test/java/generic/ExampleImageNameSubstitutor.java similarity index 100% rename from docs/examples/junit4/generic/src/test/java/generic/ExampleImageNameSubstitutor.java rename to docs/examples/junit5/generic/src/test/java/generic/ExampleImageNameSubstitutor.java diff --git a/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java b/docs/examples/junit5/generic/src/test/java/generic/ExecTest.java similarity index 73% rename from docs/examples/junit4/generic/src/test/java/generic/ExecTest.java rename to docs/examples/junit5/generic/src/test/java/generic/ExecTest.java index 078e177242f..bd49d5a7a4d 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ExecTest.java +++ b/docs/examples/junit5/generic/src/test/java/generic/ExecTest.java @@ -1,18 +1,19 @@ package generic; -import org.junit.Rule; -import org.junit.Test; -import org.testcontainers.containers.Container; +import org.junit.jupiter.api.Test; import org.testcontainers.containers.GenericContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.utility.DockerImageName; import java.io.IOException; import static org.assertj.core.api.Assertions.assertThat; +@Testcontainers public class ExecTest { - @Rule + @Container public GenericContainer container = new GenericContainer<>(DockerImageName.parse("alpine:3.17")) .withCommand("top"); @@ -23,7 +24,7 @@ public void testSimpleExec() throws IOException, InterruptedException { // } // execReadingStdout { - Container.ExecResult lsResult = container.execInContainer("ls", "-al", "/"); + org.testcontainers.containers.Container.ExecResult lsResult = container.execInContainer("ls", "-al", "/"); String stdout = lsResult.getStdout(); int exitCode = lsResult.getExitCode(); assertThat(stdout).contains("somefile.txt"); diff --git a/docs/examples/junit4/generic/src/test/java/generic/HostPortExposedTest.java b/docs/examples/junit5/generic/src/test/java/generic/HostPortExposedTest.java similarity index 83% rename from docs/examples/junit4/generic/src/test/java/generic/HostPortExposedTest.java rename to docs/examples/junit5/generic/src/test/java/generic/HostPortExposedTest.java index 392fb22c2a9..d7fe26fb2bd 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/HostPortExposedTest.java +++ b/docs/examples/junit5/generic/src/test/java/generic/HostPortExposedTest.java @@ -1,27 +1,28 @@ package generic; import com.sun.net.httpserver.HttpServer; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.remote.RemoteWebDriver; -import org.testcontainers.Testcontainers; import org.testcontainers.containers.BrowserWebDriverContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; import java.io.OutputStream; import java.net.InetSocketAddress; import static org.assertj.core.api.Assertions.assertThat; +@Testcontainers public class HostPortExposedTest { private static HttpServer server; private static int localServerPort; - @BeforeClass + @BeforeAll public static void setUp() throws Exception { server = HttpServer.create(new InetSocketAddress(0), 0); server.createContext( @@ -40,16 +41,16 @@ public static void setUp() throws Exception { localServerPort = server.getAddress().getPort(); // exposePort { - Testcontainers.exposeHostPorts(localServerPort); + org.testcontainers.Testcontainers.exposeHostPorts(localServerPort); // } } - @AfterClass + @AfterAll public static void tearDown() throws Exception { server.stop(0); } - @Rule + @Container public BrowserWebDriverContainer browser = new BrowserWebDriverContainer<>() .withCapabilities(new ChromeOptions()); diff --git a/docs/examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java b/docs/examples/junit5/generic/src/test/java/generic/ImageNameSubstitutionTest.java similarity index 97% rename from docs/examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java rename to docs/examples/junit5/generic/src/test/java/generic/ImageNameSubstitutionTest.java index ce17637cb83..a74d33fe83e 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java +++ b/docs/examples/junit5/generic/src/test/java/generic/ImageNameSubstitutionTest.java @@ -1,7 +1,7 @@ package generic; import generic.support.TestSpecificImageNameSubstitutor; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.testcontainers.containers.MySQLContainer; import org.testcontainers.utility.DockerImageName; diff --git a/docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java b/docs/examples/junit5/generic/src/test/java/generic/MultiplePortsExposedTest.java similarity index 85% rename from docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java rename to docs/examples/junit5/generic/src/test/java/generic/MultiplePortsExposedTest.java index 49e62cff217..b9e576f571f 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java +++ b/docs/examples/junit5/generic/src/test/java/generic/MultiplePortsExposedTest.java @@ -1,19 +1,21 @@ package generic; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.output.Slf4jLogConsumer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.utility.DockerImageName; +@Testcontainers public class MultiplePortsExposedTest { private static final Logger log = LoggerFactory.getLogger(MultiplePortsExposedTest.class); - @Rule - // rule { + @Container + // container { public GenericContainer container = new GenericContainer<>( DockerImageName.parse("testcontainers/helloworld:1.1.0") ) diff --git a/docs/examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java b/docs/examples/junit5/generic/src/test/java/generic/WaitStrategiesTest.java similarity index 91% rename from docs/examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java rename to docs/examples/junit5/generic/src/test/java/generic/WaitStrategiesTest.java index c66fc9443d0..578477c4f8f 100644 --- a/docs/examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java +++ b/docs/examples/junit5/generic/src/test/java/generic/WaitStrategiesTest.java @@ -1,25 +1,27 @@ package generic; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.testcontainers.containers.GenericContainer; import org.testcontainers.containers.wait.strategy.HttpWaitStrategy; import org.testcontainers.containers.wait.strategy.Wait; import org.testcontainers.containers.wait.strategy.WaitStrategy; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.utility.DockerImageName; import static org.assertj.core.api.Assertions.assertThat; +@Testcontainers public class WaitStrategiesTest { - @Rule + @Container // waitForNetworkListening { public GenericContainer nginx = new GenericContainer(DockerImageName.parse("nginx:1.27.0-alpine3.19-slim")) // .withExposedPorts(80); // } - @Rule + @Container // waitForSimpleHttp { public GenericContainer nginxWithHttpWait = new GenericContainer( DockerImageName.parse("nginx:1.27.0-alpine3.19-slim") @@ -29,7 +31,7 @@ public class WaitStrategiesTest { // } - @Rule + @Container // logMessageWait { public GenericContainer containerWithLogWait = new GenericContainer(DockerImageName.parse("redis:6-alpine")) .withExposedPorts(6379) diff --git a/docs/examples/junit4/generic/src/test/java/generic/support/TestSpecificImageNameSubstitutor.java b/docs/examples/junit5/generic/src/test/java/generic/support/TestSpecificImageNameSubstitutor.java similarity index 100% rename from docs/examples/junit4/generic/src/test/java/generic/support/TestSpecificImageNameSubstitutor.java rename to docs/examples/junit5/generic/src/test/java/generic/support/TestSpecificImageNameSubstitutor.java diff --git a/docs/examples/junit5/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java b/docs/examples/junit5/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java new file mode 100644 index 00000000000..0195b79788b --- /dev/null +++ b/docs/examples/junit5/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java @@ -0,0 +1,93 @@ +package org.testcontainers.containers.startupcheck; + +import lombok.SneakyThrows; +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.output.OutputFrame; +import org.testcontainers.containers.output.WaitingConsumer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import java.time.Duration; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import static org.assertj.core.api.Assertions.assertThat; + +@Testcontainers +public class StartupCheckStrategyTest { + + private static final String HELLO_TESTCONTAINERS = "Hello Testcontainers!"; + + private static void waitForHello(GenericContainer container) throws TimeoutException { + WaitingConsumer consumer = new WaitingConsumer(); + container.followOutput(consumer, OutputFrame.OutputType.STDOUT); + + consumer.waitUntil(frame -> frame.getUtf8String().contains(HELLO_TESTCONTAINERS), 30, TimeUnit.SECONDS); + } + + @Container + // spotless:off + // withOneShotStrategy { + public GenericContainer bboxWithOneShot = new GenericContainer<>(DockerImageName.parse("busybox:1.31.1")) + .withCommand(String.format("echo %s", HELLO_TESTCONTAINERS)) + .withStartupCheckStrategy( + new OneShotStartupCheckStrategy().withTimeout(Duration.ofSeconds(3)) + ); + + // } + // spotless:on + + @Container + // spotless:off + // withIndefiniteOneShotStrategy { + public GenericContainer bboxWithIndefiniteOneShot = new GenericContainer<>( + DockerImageName.parse("busybox:1.31.1") + ) + .withCommand("sh", "-c", String.format("sleep 5 && echo \"%s\"", HELLO_TESTCONTAINERS)) + .withStartupCheckStrategy( + new IndefiniteWaitOneShotStartupCheckStrategy() + ); + + // } + // spotless:on + + @Container + // spotless:off + // withMinimumDurationStrategy { + public GenericContainer bboxWithMinimumDuration = new GenericContainer<>( + DockerImageName.parse("busybox:1.31.1") + ) + .withCommand("sh", "-c", String.format("sleep 5 && echo \"%s\"", HELLO_TESTCONTAINERS)) + .withStartupCheckStrategy( + new MinimumDurationRunningStartupCheckStrategy(Duration.ofSeconds(1)) + ); + + // } + // spotless:on + + @SneakyThrows + @Test + public void testOneShotCommandIsExecuted() { + waitForHello(bboxWithOneShot); + + assertThat(bboxWithOneShot.isRunning()).isFalse(); + } + + @SneakyThrows + @Test + public void testIndefiniteOneShotCommandIsExecuted() { + waitForHello(bboxWithIndefiniteOneShot); + + assertThat(bboxWithIndefiniteOneShot.isRunning()).isFalse(); + } + + @SneakyThrows + @Test + public void testMinimumDurationCommandIsExecuted() { + assertThat(bboxWithMinimumDuration.isRunning()).isTrue(); + + waitForHello(bboxWithMinimumDuration); + } +} diff --git a/docs/examples/junit4/generic/src/test/resources/logback-test.xml b/docs/examples/junit5/generic/src/test/resources/logback-test.xml similarity index 100% rename from docs/examples/junit4/generic/src/test/resources/logback-test.xml rename to docs/examples/junit5/generic/src/test/resources/logback-test.xml diff --git a/docs/examples/junit4/generic/src/test/resources/testcontainers.properties b/docs/examples/junit5/generic/src/test/resources/testcontainers.properties similarity index 100% rename from docs/examples/junit4/generic/src/test/resources/testcontainers.properties rename to docs/examples/junit5/generic/src/test/resources/testcontainers.properties diff --git a/docs/features/advanced_options.md b/docs/features/advanced_options.md index e979da9ecdf..6dfb778e290 100644 --- a/docs/features/advanced_options.md +++ b/docs/features/advanced_options.md @@ -5,13 +5,13 @@ To add a custom label to the container, use `withLabel`: -[Adding a single label](../examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java) inside_block:single_label +[Adding a single label](../examples/junit5/generic/src/test/java/generic/ContainerLabelTest.java) inside_block:single_label Additionally, multiple labels may be applied together from a map: -[Adding multiple labels](../examples/junit4/generic/src/test/java/generic/ContainerLabelTest.java) inside_block:multiple_labels +[Adding multiple labels](../examples/junit5/generic/src/test/java/generic/ContainerLabelTest.java) inside_block:multiple_labels ## Image Pull Policy @@ -57,13 +57,13 @@ It is possible to use the [`docker-java`](https://github.com/docker-java/docker- For example, this can be used to change the container hostname: -[Using modifier to change hostname](../examples/junit4/generic/src/test/java/generic/CmdModifierTest.java) inside_block:hostname +[Using modifier to change hostname](../examples/junit5/generic/src/test/java/generic/CmdModifierTest.java) inside_block:hostname ... or modify container memory (see [this](https://fabiokung.com/2014/03/13/memory-inside-linux-containers/) if it does not appear to work): -[Using modifier to change memory limits](../examples/junit4/generic/src/test/java/generic/CmdModifierTest.java) inside_block:memory +[Using modifier to change memory limits](../examples/junit5/generic/src/test/java/generic/CmdModifierTest.java) inside_block:memory !!! note diff --git a/docs/features/commands.md b/docs/features/commands.md index 40bcce5d1ab..b2901831b76 100644 --- a/docs/features/commands.md +++ b/docs/features/commands.md @@ -5,7 +5,7 @@ By default the container will execute whatever command is specified in the image's Dockerfile. To override this, and specify a different command, use `withCommand`. For example: -[Specifying a startup command](../examples/junit4/generic/src/test/java/generic/CommandsTest.java) inside_block:startupCommand +[Specifying a startup command](../examples/junit5/generic/src/test/java/generic/CommandsTest.java) inside_block:startupCommand ## Executing a command @@ -13,13 +13,13 @@ By default the container will execute whatever command is specified in the image Your test can execute a command inside a running container, similar to a `docker exec` call: -[Executing a command inside a running container](../examples/junit4/generic/src/test/java/generic/ExecTest.java) inside_block:standaloneExec +[Executing a command inside a running container](../examples/junit5/generic/src/test/java/generic/ExecTest.java) inside_block:standaloneExec This can be useful for software that has a command line administration tool. You can also get the output (stdout/stderr) and exit code from the command - for example: -[Executing a command inside a running container and reading the result](../examples/junit4/generic/src/test/java/generic/ExecTest.java) inside_block:execReadingStdout +[Executing a command inside a running container and reading the result](../examples/junit5/generic/src/test/java/generic/ExecTest.java) inside_block:execReadingStdout ## Environment variables diff --git a/docs/features/image_name_substitution.md b/docs/features/image_name_substitution.md index 0948e9fa2c7..5add52ec4ff 100644 --- a/docs/features/image_name_substitution.md +++ b/docs/features/image_name_substitution.md @@ -32,13 +32,13 @@ This approach simply entails modifying test code manually, e.g. changing: For example, you may have a test that uses the `mysql` container image from Docker Hub: -[Direct Docker Hub image name](../examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java) inside_block:directDockerHubReference +[Direct Docker Hub image name](../examples/junit5/generic/src/test/java/generic/ImageNameSubstitutionTest.java) inside_block:directDockerHubReference to: -[Private registry image name](../examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java) inside_block:hardcodedMirror +[Private registry image name](../examples/junit5/generic/src/test/java/generic/ImageNameSubstitutionTest.java) inside_block:hardcodedMirror @@ -59,7 +59,7 @@ In this case, image name references in code are **unchanged**. i.e. you would leave as-is: -[Unchanged direct Docker Hub image name](../examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java) inside_block:directDockerHubReference +[Unchanged direct Docker Hub image name](../examples/junit5/generic/src/test/java/generic/ImageNameSubstitutionTest.java) inside_block:directDockerHubReference You can then configure Testcontainers to apply the prefix `registry.mycompany.com/mirror/` to every image that it tries to pull from Docker Hub. @@ -93,7 +93,7 @@ In this case, image name references in code are **unchanged**. i.e. you would leave as-is: -[Unchanged direct Docker Hub image name](../examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java) inside_block:directDockerHubReference +[Unchanged direct Docker Hub image name](../examples/junit5/generic/src/test/java/generic/ImageNameSubstitutionTest.java) inside_block:directDockerHubReference You can implement a custom image name substitutor by: @@ -104,7 +104,7 @@ You can implement a custom image name substitutor by: The following is an example image substitutor implementation: -[Example Image Substitutor](../examples/junit4/generic/src/test/java/generic/ExampleImageNameSubstitutor.java) block:ExampleImageNameSubstitutor +[Example Image Substitutor](../examples/junit5/generic/src/test/java/generic/ExampleImageNameSubstitutor.java) block:ExampleImageNameSubstitutor Testcontainers can be configured to find it at runtime via configuration. @@ -149,7 +149,7 @@ In this case, image name references in code are left **unchanged**. i.e. you would leave as-is: -[Unchanged direct Docker Hub image name](../examples/junit4/generic/src/test/java/generic/ImageNameSubstitutionTest.java) inside_block:directDockerHubReference +[Unchanged direct Docker Hub image name](../examples/junit5/generic/src/test/java/generic/ImageNameSubstitutionTest.java) inside_block:directDockerHubReference You can force Testcontainers to substitute in a different image [using a configuration file](./configuration.md), which allows some (but not all) container names to be substituted. diff --git a/docs/features/networking.md b/docs/features/networking.md index 7ecf929da16..c65febafd1c 100644 --- a/docs/features/networking.md +++ b/docs/features/networking.md @@ -8,7 +8,7 @@ For example, you may be testing a class that needs to connect to a backend or da Generally, each required port needs to be explicitly exposed. For example, we can specify one or more ports as follows: -[Exposing ports](../examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:rule +[Exposing ports](../examples/junit5/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:container Note that this exposed port number is from the *perspective of the container*. @@ -20,7 +20,7 @@ Because there is this layer of indirection, it is necessary to ask Testcontainer This can be done using the `getMappedPort` method, which takes the original (container) port as an argument: -[Retrieving actual ports at runtime](../examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:fetchPortsByNumber +[Retrieving actual ports at runtime](../examples/junit5/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:fetchPortsByNumber !!! warning @@ -30,7 +30,7 @@ This can be done using the `getMappedPort` method, which takes the original (con There is also a `getFirstMappedPort` method for convenience, for the fairly common scenario of a container that only exposes one port: -[Retrieving the first mapped port](../examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:fetchFirstMappedPort +[Retrieving the first mapped port](../examples/junit5/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:fetchFirstMappedPort ## Getting the container host @@ -41,13 +41,13 @@ However, in some CI environments they may instead be reachable on a different ho As such, Testcontainers provides a convenience method to obtain an address on which the container should be reachable from the host machine. -[Getting the container host](../examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:getHostOnly +[Getting the container host](../examples/junit5/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:getHostOnly It is normally advisable to use `getHost` and `getMappedPort` together when constructing addresses - for example: -[Getting the container host and mapped port](../examples/junit4/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:getHostAndMappedPort +[Getting the container host and mapped port](../examples/junit5/generic/src/test/java/generic/MultiplePortsExposedTest.java) inside_block:getHostAndMappedPort !!! tip @@ -65,7 +65,7 @@ In this example, assume that `localServerPort` is a port on our test host machin We need to tell Testcontainers to prepare to expose this port to containers: -[Exposing the host port](../examples/junit4/generic/src/test/java/generic/HostPortExposedTest.java) inside_block:exposePort +[Exposing the host port](../examples/junit5/generic/src/test/java/generic/HostPortExposedTest.java) inside_block:exposePort !!! warning @@ -78,7 +78,7 @@ From a container's perspective, the hostname will be `host.testcontainers.intern For example, here we construct an HTTP URL for our local web application and tell a Selenium container to get a page from it: -[Accessing the exposed host port from a container](../examples/junit4/generic/src/test/java/generic/HostPortExposedTest.java) inside_block:useHostExposedPort +[Accessing the exposed host port from a container](../examples/junit5/generic/src/test/java/generic/HostPortExposedTest.java) inside_block:useHostExposedPort diff --git a/docs/features/startup_and_waits.md b/docs/features/startup_and_waits.md index d760dfa93d0..d0680955828 100644 --- a/docs/features/startup_and_waits.md +++ b/docs/features/startup_and_waits.md @@ -14,7 +14,7 @@ Ordinarily Testcontainers will wait for up to 60 seconds for the container's fir This simple measure provides a basic check whether a container is ready for use. -[Waiting for the first exposed port to start listening](../examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForNetworkListening +[Waiting for the first exposed port to start listening](../examples/junit5/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForNetworkListening If the default 60s timeout is not sufficient, it can be altered with the `withStartupTimeout()` method. @@ -28,24 +28,24 @@ You can choose to wait for an HTTP(S) endpoint to return a particular status cod #### Waiting for 200 OK -[](../examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForSimpleHttp +[](../examples/junit5/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForSimpleHttp Variations on the HTTP wait strategy are supported, including: #### Waiting for multiple possible status codes -[](../examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForHttpWithMultipleStatusCodes +[](../examples/junit5/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForHttpWithMultipleStatusCodes #### Waiting for a status code that matches a predicate -[Waiting for a status code that matches a predicate](../examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForHttpWithStatusCodePredicate +[Waiting for a status code that matches a predicate](../examples/junit5/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForHttpWithStatusCodePredicate #### Using TLS -[](../examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForHttpWithTls +[](../examples/junit5/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:waitForHttpWithTls ### Healthcheck Wait strategy examples @@ -53,7 +53,7 @@ Variations on the HTTP wait strategy are supported, including: If the used image supports Docker's [Healthcheck](https://docs.docker.com/engine/reference/builder/#healthcheck) feature, you can directly leverage the `healthy` state of the container as your wait condition: -[](../examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:healthcheckWait +[](../examples/junit5/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:healthcheckWait ### Log output Wait Strategy @@ -62,7 +62,7 @@ In some situations a container's log output is a simple way to determine if it i For example, we can wait for a `Ready' message in the container's logs as follows: -[](../examples/junit4/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:logMessageWait +[](../examples/junit5/generic/src/test/java/generic/WaitStrategiesTest.java) inside_block:logMessageWait ### Other Wait Strategies @@ -94,7 +94,7 @@ This strategy is intended for use with containers that only run briefly and exit the container has stopped with exit code 0. -[Using one shot startup strategy](../examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java) inside_block:withOneShotStrategy +[Using one shot startup strategy](../examples/junit5/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java) inside_block:withOneShotStrategy ### Indefinite one shot startup strategy example @@ -105,7 +105,7 @@ Variant of one shot strategy that does not impose a timeout. Intended for situat It has to be assumed that the container will stop of its own accord, either with a success or failure exit code. -[Using indefinite one shot startup strategy](../examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java) inside_block:withIndefiniteOneShotStrategy +[Using indefinite one shot startup strategy](../examples/junit5/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java) inside_block:withIndefiniteOneShotStrategy ### Minimum duration startup strategy example @@ -113,7 +113,7 @@ It has to be assumed that the container will stop of its own accord, either with Checks that the container is running and has been running for a defined minimum period of time. -[Using minimum duration strategy](../examples/junit4/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java) inside_block:withMinimumDurationStrategy +[Using minimum duration strategy](../examples/junit5/generic/src/test/java/org/testcontainers/containers/startupcheck/StartupCheckStrategyTest.java) inside_block:withMinimumDurationStrategy ### Other startup strategies @@ -129,5 +129,5 @@ Or you can leave it as is and just implement the `checkStartupState(DockerClient Sometimes, a container relies on another container to be ready before it should start itself. An example of this might be a database that needs to be started before your application container can link to it. You can tell a container that it depends on another container by using the `dependsOn` method: -[Depending on another container](../examples/junit4/generic/src/test/java/generic/DependsOnTest.java) inside_block:dependsOn +[Depending on another container](../examples/junit5/generic/src/test/java/generic/DependsOnTest.java) inside_block:dependsOn diff --git a/docs/index.md b/docs/index.md index 40304dd22ed..fe53f618e4b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -27,10 +27,9 @@ Testcontainers make the following kinds of tests easier: * Docker - please see [General Docker requirements](supported_docker_environment/index.md) * A supported JVM testing framework: - * [JUnit 4](test_framework_integration/junit_4.md) - See the [JUnit 4 Quickstart Guide](quickstart/junit_4_quickstart.md) * [Jupiter/JUnit 5](test_framework_integration/junit_5.md) * [Spock](test_framework_integration/spock.md) - * *Or* manually add code to control the container/test lifecycle (See [hints for this approach](test_framework_integration/junit_4.md#manually-controlling-container-lifecycle)) + * *Or* manually add code to control the container/test lifecycle (See [manual lifecycle control](test_framework_integration/manual_lifecycle_control.md)) ## Maven dependencies diff --git a/docs/modules/databases/jdbc.md b/docs/modules/databases/jdbc.md index 72539aef44e..fe3d4c04cc3 100644 --- a/docs/modules/databases/jdbc.md +++ b/docs/modules/databases/jdbc.md @@ -3,7 +3,7 @@ You can obtain a temporary database in one of two ways: * **Using a specially modified JDBC URL**: after making a very simple modification to your system's JDBC URL string, Testcontainers will provide a disposable stand-in database that can be used without requiring modification to your application code. - * **JUnit @Rule/@ClassRule**: this mode starts a database inside a container before your tests and tears it down afterwards. + * **Database container objects**: this mode starts a database inside a container before your tests and tears it down afterwards. ## Database containers launched via JDBC URL scheme @@ -154,11 +154,12 @@ For more information about `tmpfs` mount, see [the official Docker documentation In case you can't use the URL support, or need to fine-tune the container, you can instantiate it yourself. -Add a @Rule or @ClassRule to your test class, e.g.: +Add a `@Container` field to your JUnit Jupiter test class, e.g.: ```java +@Testcontainers public class SimpleMySQLTest { - @Rule + @Container public MySQLContainer mysql = new MySQLContainer(); ``` @@ -168,7 +169,7 @@ Now, in your test code (or a suitable setup method), you can obtain details nece * `mysql.getUsername()` provides the username your code should pass to the driver * `mysql.getPassword()` provides the password your code should pass to the driver -Note that if you use `@Rule`, you will be given an isolated container for each test method. If you use `@ClassRule`, you will get on isolated container for all the methods in the test class. +Note that if you use an instance field, you will be given an isolated container for each test method. If you use a static field, you will get one isolated container for all the methods in the test class. Examples/Tests: diff --git a/docs/modules/databases/presto.md b/docs/modules/databases/presto.md index 4e9a6e7c95d..d5e136e4402 100644 --- a/docs/modules/databases/presto.md +++ b/docs/modules/databases/presto.md @@ -10,9 +10,10 @@ See [Database containers](./index.md) for documentation and usage that is common Running Presto as a stand-in for in a test: ```java +@Testcontainers public class SomeTest { - @Rule + @Container public PrestoContainer presto = new PrestoContainer(); @Test @@ -34,8 +35,9 @@ Presto comes with several catalogs preconfigured. Most useful ones for testing a Example test using the `tpch` and `memory` catalogs: ```java +@Testcontainers public class SomeTest { - @Rule + @Container public PrestoContainer prestoSql = new PrestoContainer(); @Test @@ -56,7 +58,7 @@ public class SomeTest { while (resultSet.next()) { actualElements.add(resultSet.getInt("element")); } - Assert.assertEquals(Arrays.asList(2, 4, 42, 42, 42), actualElements); + assertThat(actualElements).isEqualTo(Arrays.asList(2, 4, 42, 42, 42)); } } } @@ -86,4 +88,3 @@ Add the following dependency to your `pom.xml`/`build.gradle` file: You should ensure that your project has the Presto JDBC driver as a dependency, if you plan on using it. Refer to [Presto project download page](https://prestosql.io/download.html) for instructions. - diff --git a/docs/modules/databases/r2dbc.md b/docs/modules/databases/r2dbc.md index 91580811887..99e4fbd10e3 100644 --- a/docs/modules/databases/r2dbc.md +++ b/docs/modules/databases/r2dbc.md @@ -3,7 +3,7 @@ You can obtain a temporary database in one of two ways: * **Using a specially modified R2DBC URL**: after making a very simple modification to your system's R2DBC URL string, Testcontainers will provide a disposable stand-in database that can be used without requiring modification to your application code. - * **JUnit @Rule/@ClassRule**: this mode starts a database inside a container before your tests and tears it down afterwards. + * **Database container objects**: this mode starts a database inside a container before your tests and tears it down afterwards. ## Database containers launched via R2DBC URL scheme diff --git a/docs/quickstart/junit_4_quickstart.md b/docs/quickstart/junit_4_quickstart.md deleted file mode 100644 index 57946c1fb74..00000000000 --- a/docs/quickstart/junit_4_quickstart.md +++ /dev/null @@ -1,83 +0,0 @@ -# JUnit 4 Quickstart - -It's easy to add Testcontainers to your project - let's walk through a quick example to see how. - -Let's imagine we have a simple program that has a dependency on Redis, and we want to add some tests for it. -In our imaginary program, there is a `RedisBackedCache` class which stores data in Redis. - -You can see an example test that could have been written for it (without using Testcontainers): - - -[Pre-Testcontainers test code](../examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTestStep0.java) block:RedisBackedCacheIntTestStep0 - - -Notice that the existing test has a problem - it's relying on a local installation of Redis, which is a red flag for test reliability. -This may work if we were sure that every developer and CI machine had Redis installed, but would fail otherwise. -We might also have problems if we attempted to run tests in parallel, such as state bleeding between tests, or port clashes. - -Let's start from here, and see how to improve the test with Testcontainers: - -## 1. Add Testcontainers as a test-scoped dependency - -First, add Testcontainers as a dependency as follows: - -=== "Gradle" - ```groovy - testImplementation "org.testcontainers:testcontainers:{{latest_version}}" - ``` -=== "Maven" - ```xml - - org.testcontainers - testcontainers - {{latest_version}} - test - - ``` - -## 2. Get Testcontainers to run a Redis container during our tests - -Simply add the following to the body of our test class: - - -[JUnit 4 Rule](../examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java) inside_block:rule - - -The `@Rule` annotation tells JUnit to notify this field about various events in the test lifecycle. -In this case, our rule object is a Testcontainers `GenericContainer`, configured to use a specific Redis image from Docker Hub, and configured to expose a port. - -If we run our test as-is, then regardless of the actual test outcome, we'll see logs showing us that Testcontainers: - -* was activated before our test method ran -* discovered and quickly tested our local Docker setup -* pulled the image if necessary -* started a new container and waited for it to be ready -* shut down and deleted the container after the test - -## 3. Make sure our code can talk to the container - -Before Testcontainers, we might have hardcoded an address like `localhost:6379` into our tests. - -Testcontainers uses *randomized ports* for each container it starts, but makes it easy to obtain the actual port at runtime. -We can do this in our test `setUp` method, to set up our component under test: - - -[Obtaining a mapped port](../examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java) inside_block:setUp - - -!!! tip - Notice that we also ask Testcontainers for the container's actual address with `redis.getHost();`, - rather than hard-coding `localhost`. `localhost` may work in some environments but not others - for example it may - not work on your current or future CI environment. As such, **avoid hard-coding** the address, and use - `getHost()` instead. - -## 4. Run the tests! - -That's it! - -Let's look at our complete test class to see how little we had to add to get up and running with Testcontainers: - - -[RedisBackedCacheIntTest](../examples/junit4/redis/src/test/java/quickstart/RedisBackedCacheIntTest.java) block:RedisBackedCacheIntTest - - diff --git a/docs/test_framework_integration/junit_4.md b/docs/test_framework_integration/junit_4.md deleted file mode 100644 index 8ab753e611f..00000000000 --- a/docs/test_framework_integration/junit_4.md +++ /dev/null @@ -1,46 +0,0 @@ -# JUnit 4 - -## `@Rule`/`@ClassRule` integration - -**JUnit4 `@Rule`/`@ClassRule`**: This mode starts the container before your tests and tears it down afterwards. - -Add a `@Rule` or `@ClassRule` annotated field to your test class, e.g.: - -```java -public class SimpleMySQLTest { - @Rule - public MySQLContainer mysql = new MySQLContainer(); - - // [...] -} -``` - - -## Manually controlling container lifecycle - -As an alternative, you can manually start the container in a `@BeforeClass`/`@Before` annotated method in your tests. Tear down will be done automatically on JVM exit, but you can of course also use an `@AfterClass`/`@After` annotated method to manually call the `stop()` method on your container. - -*Example of starting a container in a `@Before` annotated method:* - -```java -class SimpleMySQLTest { - private MySQLContainer mysql = new MySQLContainer(); - - @Before - void before() { - mysql.start(); - } - - @After - void after() { - mysql.stop(); - } - - // [...] -} -``` - -## Singleton containers - -Note that the [singleton container pattern](manual_lifecycle_control.md#singleton-containers) is also an option when -using JUnit 4. diff --git a/mkdocs.yml b/mkdocs.yml index ad75b0b2f22..618a0ec0992 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -30,7 +30,6 @@ markdown_extensions: nav: - Home: index.md - Quickstart: - - quickstart/junit_4_quickstart.md - quickstart/junit_5_quickstart.md - quickstart/spock_quickstart.md - Features: @@ -111,7 +110,6 @@ nav: - modules/weaviate.md - modules/webdriver_containers.md - Test framework integration: - - test_framework_integration/junit_4.md - test_framework_integration/junit_5.md - test_framework_integration/spock.md - test_framework_integration/manual_lifecycle_control.md diff --git a/settings.gradle b/settings.gradle index d59d26df2df..9c1c74907d4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -28,6 +28,7 @@ file('modules').eachDir { dir -> } include ':docs:examples:junit5:redis' +include ':docs:examples:junit5:generic' include ':docs:examples:spock:redis' include 'test-support'