I'm attempting to use the latest best practices for Spring Boot 3.x and TestContainers to integration test a MongoDB Repository. From a post on the Spring.io blog:
Under the covers, @ServiceConnection discovers the type of container that is annotated and creates a ConnectionDetails bean for it. This replaces the need for the @DynamicPropertySource code, so you can just remove it.
Because I have several MongoDb integration tests, I setup an Abstract test class that creates a static MongoDb container under the hood:
@SpringBootTest
@Testcontainers(disabledWithoutDocker = true)
public abstract class MongoContainerTest {
@Container
@ServiceConnection
static MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:7.0.9-rc1");
}
and then my test class extends it:
class RoleRepositoryTest extends MongoContainerTest {
@Autowired
RoleRepository roleRepository;
private Role expectedRole;
@BeforeEach
void setUp() {
roleRepository.deleteAll();
}
@Test
void testFind() {...}
}
Run individually, these tests work just fine. However, when I attempt to run them all as part of a test suite from maven or Intellij, only the first MongoContainerTest
child works, while the rest give an error:
INFO org.mongodb.driver.cluster Exception in monitor thread while connecting to server localhost:55114
com.mongodb.MongoSocketOpenException: Exception opening socket
at com.mongodb.internal.connection.SocketStream.lambda$open$0(SocketStream.java:84)
at java.base/java.util.Optional.orElseThrow(Optional.java:403)
at com.mongodb.internal.connection.SocketStream.open(SocketStream.java:84)
at com.mongodb.internal.connection.InternalStreamConnection.open(InternalStreamConnection.java:211)
at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.lookupServerDescription(DefaultServerMonitor.java:196)
at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:156)
at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.net.ConnectException: Connection refused
at java.base/sun.nio.ch.Net.pollConnect(Native Method)
at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:682)
I tried different things to get this configuration working. Such as setting the .withReuse(true)
flag on. But I keep getting the same issue. I am guessing that after the first test runs the docker container shuts down and the next test is unable to open one. Any ideas here?
My takeaway is, for persisting the container across tests in the manner I am describing, use of @ServiceConnection
is a no-go. My abstract test was modified to:
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.MongoDBContainer;
import org.testcontainers.junit.jupiter.Testcontainers;
/**
* Base class for tests that require a running MongoDB container.
* Simply extend to inherit a spring-managed mongo repository
*/
@SpringBootTest
@Testcontainers
public abstract class MongoContainerTest {
protected static final MongoDBContainer mongoDBContainer;
static {
mongoDBContainer = new MongoDBContainer("mongo:<your_version_here>");
mongoDBContainer.start();
}
@DynamicPropertySource
static void setProperties(DynamicPropertyRegistry registry) {
registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl);
}
}
At that point, I can create a mongo integration test by simple extending this class and Autowiring the repository-under-test into my unit test class.