From e56cdd783a2b857561d95f64425e43e48e29abf9 Mon Sep 17 00:00:00 2001 From: Caio Vinicius Date: Sun, 18 Oct 2026 01:16:18 -0300 Subject: [PATCH] Explain missing JDBC driver for R2DBC users of MySQL, MariaDB and MSSQL MySQLContainer, MariaDBContainer and MSSQLServerContainer use the default JdbcDatabaseContainer startup check, which connects over JDBC. Projects that only use R2DBC therefore still need the JDBC driver on the test classpath, and without it the container fails with a bare "Could not get Driver". - Name the driver class in the NoDriverFoundException message and say why it is needed, also when the application only uses R2DBC - Document the requirement in the R2DBC page and in the MySQL, MariaDB and MS SQL Server module pages - Add a unit test for the message that does not need Docker --- docs/modules/databases/mariadb.md | 1 + docs/modules/databases/mssqlserver.md | 1 + docs/modules/databases/mysql.md | 1 + docs/modules/databases/r2dbc.md | 3 +++ .../containers/JdbcDatabaseContainer.java | 9 ++++++++- .../testcontainers/jdbc/MissingJdbcDriverTest.java | 12 ++++++++++++ 6 files changed, 26 insertions(+), 1 deletion(-) diff --git a/docs/modules/databases/mariadb.md b/docs/modules/databases/mariadb.md index d90f9381cb5..d09a16b9ae5 100644 --- a/docs/modules/databases/mariadb.md +++ b/docs/modules/databases/mariadb.md @@ -44,4 +44,5 @@ Add the following dependency to your `pom.xml`/`build.gradle` file: !!! hint Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency. + The JDBC driver is required even if your application only uses R2DBC, because the container startup check connects over JDBC. diff --git a/docs/modules/databases/mssqlserver.md b/docs/modules/databases/mssqlserver.md index 5c9d7b0a9fb..bd7f0f0bfe3 100644 --- a/docs/modules/databases/mssqlserver.md +++ b/docs/modules/databases/mssqlserver.md @@ -44,6 +44,7 @@ Add the following dependency to your `pom.xml`/`build.gradle` file: !!! hint Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency. + The JDBC driver is required even if your application only uses R2DBC, because the container startup check connects over JDBC. ## License diff --git a/docs/modules/databases/mysql.md b/docs/modules/databases/mysql.md index 1747989766f..6b539223e08 100644 --- a/docs/modules/databases/mysql.md +++ b/docs/modules/databases/mysql.md @@ -54,3 +54,4 @@ Add the following dependency to your `pom.xml`/`build.gradle` file: !!! hint Adding this Testcontainers library JAR will not automatically add a database driver JAR to your project. You should ensure that your project also has a suitable database driver as a dependency. + The JDBC driver is required even if your application only uses R2DBC, because the container startup check connects over JDBC. diff --git a/docs/modules/databases/r2dbc.md b/docs/modules/databases/r2dbc.md index 91580811887..53cd8b892c7 100644 --- a/docs/modules/databases/r2dbc.md +++ b/docs/modules/databases/r2dbc.md @@ -14,6 +14,9 @@ The started container will be terminated when the `ConnectionFactory` is closed. !!! warning Both the database module (e.g. `org.testcontainers:testcontainers-mysql`) **and** `org.testcontainers:testcontainers-r2dbc` need to be on your application's classpath at runtime. +!!! warning + For MySQL, MariaDB and MS SQL Server, the JDBC driver also needs to be on the test classpath, even if your application only uses R2DBC. Testcontainers checks that these databases are ready by connecting over JDBC; without the driver, the container fails to start with `Could not get Driver`. + **Original URL**: `r2dbc:mysql://localhost:3306/databasename` 1. Insert `tc:` after `r2dbc:` as follows. Note that the hostname, port and database name will be ignored; you can leave these as-is or set them to any value. diff --git a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java index cf6c995528f..c4be1f77965 100644 --- a/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java +++ b/modules/jdbc/src/main/java/org/testcontainers/containers/JdbcDatabaseContainer.java @@ -232,7 +232,14 @@ public Driver getJdbcDriverInstance() throws NoDriverFoundException { try { driver = (Driver) Class.forName(this.getDriverClassName()).newInstance(); } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { - throw new NoDriverFoundException("Could not get Driver", e); + throw new NoDriverFoundException( + String.format( + "Could not get Driver %s. The JDBC driver must be on the classpath because the " + + "container startup check connects over JDBC, even if the application only uses R2DBC", + this.getDriverClassName() + ), + e + ); } } } diff --git a/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java b/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java index 469234e15a6..34e1ddde66f 100644 --- a/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java +++ b/modules/jdbc/src/test/java/org/testcontainers/jdbc/MissingJdbcDriverTest.java @@ -10,6 +10,7 @@ import java.util.concurrent.atomic.AtomicInteger; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.fail; class MissingJdbcDriverTest { @@ -35,6 +36,17 @@ void shouldFailFastIfNoDriverFound() { .isEqualTo(1); } + @Test + void shouldNameTheMissingDriverClass() { + final MissingDriverContainer container = new MissingDriverContainer(); + + assertThatThrownBy(container::getJdbcDriverInstance) + .isInstanceOf(JdbcDatabaseContainer.NoDriverFoundException.class) + .hasMessageContaining("nonexistent.ClassName") + .hasMessageContaining("R2DBC") + .hasCauseInstanceOf(ClassNotFoundException.class); + } + /** * Container class for the purposes of testing, with a known non-existent driver */