When using Testcontainers, access to the Mongo instance in the container is available via a URL which is applied using a @DynamicPropertySource:

@DynamicPropertySource
static void applicationProperties(DynamicPropertyRegistry registry) {
    registry.add("spring.data.mongodb.uri", mongo::getReplicaSetUrl);
}

This works well when main code also uses spring.data.mongodb.uri to connect to Mongo. It does not work when spring.data.mongodb.host etc have been used instead:

Caused by: java.lang.IllegalStateException: Invalid mongo configuration, either uri or host/port/credentials/replicaSet must be specified
    at org.springframework.util.Assert.state(Assert.java:76) ~[spring-core-5.3.16.jar:5.3.16]
    at org.springframework.boot.autoconfigure.mongo.MongoPropertiesClientSettingsBuilderCustomizer.validateConfiguration(MongoPropertiesClientSettingsBuilderCustomizer.java:61) ~[main/:na]
    at org.springframework.boot.autoconfigure.mongo.MongoPropertiesClientSettingsBuilderCustomizer.customize(MongoPropertiesClientSettingsBuilderCustomizer.java:52) ~[main/:na]
    at org.springframework.boot.autoconfigure.mongo.MongoClientFactorySupport.customize(MongoClientFactorySupport.java:55) ~[main/:na]
    at org.springframework.boot.autoconfigure.mongo.MongoClientFactorySupport.createMongoClient(MongoClientFactorySupport.java:49) ~[main/:na]
    at org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration.mongo(MongoAutoConfiguration.java:56) ~[main/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_252]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_252]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_252]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_252]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.3.16.jar:5.3.16]
    ... 196 common frames omitted

This can be worked around to some extent by overriding properties:

@DynamicPropertySource
static void applicationProperties(DynamicPropertyRegistry registry) {
    registry.add("spring.data.mongodb.host", () -> URI.create(mongo.getReplicaSetUrl()).getHost());
    registry.add("spring.data.mongodb.port", () -> URI.create(mongo.getReplicaSetUrl()).getPort());
    registry.add("spring.data.mongodb.replica-set-name", () -> "docker-rs");
}

However, it does not work when the main configuration has set the username and password as an override cannot remove the configuration.

We need a more robust way of overriding the main configuration from a test. This will also be of benefit to Embedded Mongo where we currently only set local.mongo.port. It's possible with more advanced embedded Mongo configuration that other settings related to Mongo connectivity must also be set and we do not do so at the moment.

Comment From: chantyapk

@DynamicPropertySource
static void applicationProperties(DynamicPropertyRegistry registry) {
    registry.add("spring.data.mongodb.host", () -> URI.create(mongo.getReplicaSetUrl()).getHost());
    registry.add("spring.data.mongodb.port", () -> URI.create(mongo.getReplicaSetUrl()).getPort());
    registry.add("spring.data.mongodb.replica-set-name", () -> "docker-rs");
}

need to add some @methods to avoid some nullpoint exceptions

Comment From: wilkinsona

There's quite a bit of precedent for a URI-like property taking precedence:

  • spring.rabbitmq.addresses take precedence over properties that configure a component of an address.
  • spring.redis.url overrides individual host, port, and password properties
  • spring.integration.rsocket.client.uri overrides the separate host and port properties.
  • spring.r2dbc.url takes precedence over separate properties

This change for Mongo will make things more consistent with these other properties.