You must disable the auto configuration provided by spring by disabling the spring provided auto configuration class:
@DataMongoTest(
excludeAutoConfiguration = org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration.class
)
@ExtendWith(SpringExtension.class)
public class AutoConfigTest {
@Test
void example(@Autowired final MongoTemplate mongoTemplate) {
Assertions.assertThat(mongoTemplate.getDb()).isNotNull();
}
}
Per default there is just one mongodb instance running. In case you need test isolation you can annotate your test
with @TestPropertySource
as in this example:
@DataMongoTest(
excludeAutoConfiguration = org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration.class
)
@TestPropertySource(properties = "property=A")
@ExtendWith(SpringExtension.class)
@DirtiesContext
public class AutoConfigFirstIsolationTest {
@Test
void example(@Autowired final MongoTemplate mongoTemplate) {
mongoTemplate.getDb().createCollection("deleteMe");
long count = mongoTemplate.getDb().getCollection("deleteMe").countDocuments(Document.parse("{}"));
assertThat(mongoTemplate.getDb()).isNotNull();
assertThat(count).isEqualTo(0L);
}
}
The tests with the same configuration will share their instance. If you want to achive test isolation with the same
configuration you must annotate your test with @DirtiesContext
so that this test will have his own mongodb:
@DataMongoTest(
excludeAutoConfiguration = org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration.class
)
@TestPropertySource(properties = "property=A")
@ExtendWith(SpringExtension.class)
@DirtiesContext
public class AutoConfigSecondIsolationTest {
@Test
void example(@Autowired final MongoTemplate mongoTemplate) {
mongoTemplate.getDb().createCollection("deleteMe");
long count = mongoTemplate.getDb().getCollection("deleteMe").countDocuments(Document.parse("{}"));
assertThat(mongoTemplate.getDb()).isNotNull();
assertThat(count).isEqualTo(0L);
}
}
If you create a bean config for a list of MongoImportArguments
a mongoimport process is started as soon as the mongodb is running but before
any test code is executed.
If mongoimport
is not bundled within the mongodb version, then you have to define a tools version: 'de.flapdoodle.mongodb.embedded.tools-version'.
@DataMongoTest()
@ExtendWith(SpringExtension.class)
@Import(ImportJsonTest.Config.class)
public class ImportJsonTest {
@Test
void example(@Autowired final MongoTemplate mongoTemplate) {
assertThat(mongoTemplate.getDb()).isNotNull();
ArrayList<Document> first = mongoTemplate.getDb()
.getCollection("first")
.find()
.into(new ArrayList<>());
assertThat(first).hasSize(3)
.anyMatch(doc -> doc.get("name", String.class).equals("Cassandra"));
ArrayList<Document> second = mongoTemplate.getDb()
.getCollection("second")
.find()
.into(new ArrayList<>());
assertThat(second).hasSize(2)
.anyMatch(doc -> doc.get("name", String.class).equals("Susi"));
}
static class Config {
@Bean
public List<MongoImportArguments> jsonImportArguments() {
return Arrays.asList(MongoImportArguments.builder()
.databaseName("test")
.collectionName("first")
.importFile(ImportJsonTest.class.getResource("/first.json").getFile())
.isJsonArray(true)
.upsertDocuments(true)
.build(),
MongoImportArguments.builder()
.databaseName("test")
.collectionName("second")
.importFile(ImportJsonTest.class.getResource("/second.json").getFile())
.isJsonArray(true)
.upsertDocuments(true)
.build());
}
}
}
To enable transactions with spring data, there is one minimal setup. Imagine you have an person repository:
public interface PersonRepository extends MongoRepository<Person,String> {
}
... which is called inside this service:
@Service
public class PersonService {
private PersonRepository repository;
@Autowired
public PersonService(PersonRepository repository) {
this.repository = repository;
}
@Transactional
public void insert(String ... names) {
for (String name : names) {
repository.insert(new Person(name.substring(0, 1), name));
}
}
public long count() {
return repository.count();
}
}
Then you must enable an MongoTransactionManager:
@Configuration
public class TransactionalConfig {
@Bean
MongoTransactionManager mongoTransactionManager(MongoDatabaseFactory dbFactory) {
return new MongoTransactionManager(dbFactory);
}
@Bean
MongodArguments mongodArguments() {
return MongodArguments.builder()
.replication(Storage.of("test", 10))
.build();
}
}
... and if we call the service from test, some calls will succeed and others will fail so that the transaction is not committed:
@AutoConfigureDataMongo
@SpringBootTest(
properties = "de.flapdoodle.mongodb.embedded.version=5.0.5"
)
@EnableAutoConfiguration(
exclude = org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration.class
)
@DirtiesContext
public class TransactionalTest {
@Test
void personExample(@Autowired PersonService service) {
service.insert("Klaus","Susi");
assertThat(service.count()).isEqualTo(2);
assertThatThrownBy(() -> service.insert("Helga","Hans"))
.isInstanceOf(RuntimeException.class);
assertThat(service.count()).isEqualTo(2);
}
}
@AutoConfigureDataMongo
@SpringBootTest(
properties = {
"de.flapdoodle.mongodb.embedded.databaseDir=${java.io.tmpdir}/customDir/${random.uuid}"
}
)
@EnableAutoConfiguration(
exclude = org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration.class
)
@DirtiesContext
public class CustomDatabaseDirTest {
@Test
void example(@Autowired final MongoTemplate mongoTemplate) {
Assertions.assertThat(mongoTemplate.getDb()).isNotNull();
}
}
If none of the other configuration options is enough, you can customize it further by adding a BeanPostProcessor
or
use a more typesafe implementation like `TypedBeanPostProcessor:
@Configuration
public class LocalConfig {
@Bean
BeanPostProcessor customizeMongod() {
return TypedBeanPostProcessor.applyBeforeInitialization(Mongod.class, src -> {
return Mongod.builder()
.from(src)
.processOutput(Start.to(ProcessOutput.class)
.initializedWith(ProcessOutput.namedConsole("custom")))
.build();
});
}
}
@AutoConfigureDataMongo
@SpringBootTest()
@EnableAutoConfiguration
@DirtiesContext
public class CustomizeMongodTest {
@Test
void example(@Autowired final MongoTemplate mongoTemplate) {
assertThat(mongoTemplate.getDb()).isNotNull();
}
}
Use 'de.flapdoodle.mongodb.embedded' as prefix in your config files.
If you want to test with an 'unmanaged' mongodb database, you must disable the auto configuration by excluding EmbeddedMongoAutoConfiguration:
@EnableAutoConfiguration(exclude = {EmbeddedMongoAutoConfiguration.class})