Reputation: 115
My question is similar to Populate a database with TestContainers in a SpringBoot integration test but instead I have a mongo db test container as follows:
@Container
private static MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:3.4.20"))
I can use mongorepository.save() but that's not really feasible as there are multiple collections and I need populate several fields (and a bunch of them are nested fields). What are some other ways to achieve the same?
Upvotes: 3
Views: 5683
Reputation: 129
Based on Testcontainers documentation and one of the answers here, I have added import in singleton container. My initial test data is stored in JSON format, so I used mongoimport
.
public class AbstractContainerBaseTest {
protected static final MongoDBContainer mongoDBContainer;
static {
mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:latest"));
mongoDBContainer.start();
mongoDBContainer.copyFileToContainer(MountableFile.forClasspathResource("/mongo/article.json"), "/article.json");
try {
mongoDBContainer.execInContainer("mongoimport", "-d", "test", "-c", "article", "--file", "/article.json", "--jsonArray");
} catch (Exception e) {
// logger
}
}
@DynamicPropertySource
static void mongoDbProperties(DynamicPropertyRegistry registry) {
registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl);
}
}
Test classes extends then this abstract class:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Testcontainers
class ArticleControllerTest extends AbstractContainerBaseTest {
}
Upvotes: 1
Reputation: 175
A way I've done it in the past when I need some initial data in the database is by adding an ApplicationContextInitializer that boots up the testcontainer and then run a mongorestore inside the container for loading a mongodump I prepared separately.
This way you can keep your dump folder in your test-resources folder. Ofcourse, if you have other files there be sure to use to the correct classpath resource path.
Hope this helps!
public class TestContainerInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@SneakyThrows
@Override
public void initialize(ConfigurableApplicationContext context) {
MongoDBContainer instance = MongoContainerSingleton.getInstance();
instance.copyFileToContainer(
MountableFile.forClasspathResource("/"), "/IT-dump");
Container.ExecResult mongorestore = instance.execInContainer("mongorestore", "/IT-dump/dump/");
}
public static class MongoContainerSingleton {
private static volatile MongoDBContainer instance = null;
public static MongoDBContainer getInstance() {
synchronized (MongoContainerSingleton.class) {
if (instance == null) {
instance = new MongoDBContainer("mongo:4.2.11")
.withReuse(true);
instance.start();
}
}
return instance;
}
}
}
Upvotes: 6
Reputation: 6530
There is a liquibase mongodb project which can be used. You can take a look at this project. There is a db.changelog-master.json where the schema creation is defined as a first changelog (you can define more) and as you can see in the test just defined the container, set the spring.data.mongodb.uri
and manually run the migration due to spring boot does not offer autoconfigure for liquibase mongodb extension.
@Container
private static final MongoDBContainer mongo = new MongoDBContainer("mongo:4.0.10");
@Autowired
private PersonRepository repository;
@DynamicPropertySource
static void mongoProperties(DynamicPropertyRegistry registry) {
registry.add("spring.data.mongodb.uri", mongo::getConnectionString);
}
@Test
void test() throws LiquibaseException {
var database = (MongoLiquibaseDatabase) DatabaseFactory.getInstance().openDatabase(mongo.getReplicaSetUrl("test"), null, null, null, null);
var liquibase = new Liquibase("db/changelog/db.changelog-master.json", new ClassLoaderResourceAccessor(), database);
liquibase.update("");
var books = this.repository.findAll();
assertThat(books).hasSize(3);
}
This sample project is based in spring boot too.
Also, check Initializing a fresh instance
Upvotes: 2
Reputation: 1572
I am not a MongoDB expert, but you should populate the database independent of the fact, that you are using Testcontainers to instrument it. So using the repository does seem right. You can also use a special repository in your test classes, to which you add methods that do bigger bootstrappings.
Also, consider stopping using the @Container
annotation, which starts a container for every test class, this can lead to a lot of startup overhead. Generally, using the Singleton Container Pattern lead to much better test suite performance.
Upvotes: 0