1. Overview
2. Configuration
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.18.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.18.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mongodb</artifactId>
<version>1.18.3</version>
<scope>test</scope>
</dependency>
2.2. Creating the Repository
Then, we’ll create our ProductRepository class extending from MongoRepository:
@Repository
public interface ProductRepository extends MongoRepository<Product, String> {
Optional<Product> findByName(String name);
}
2.3. Creating the REST Controller
Finally, let’s expose a REST API by creating a controller to interact with the repository:
@RestController
@RequestMapping("/products")
public class ProductController {
private final ProductRepository productRepository;
public ProductController(ProductRepository productRepository) {
this.productRepository = productRepository;
}
@PostMapping
public String createProduct(@RequestBody Product product) {
return productRepository.save(product)
.getId();
}
@GetMapping("/{id}")
public Product getProduct(@PathVariable String id) {
return productRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Product not found"));
}
}
3. Testcontainers MongoDB Integration Base
@Testcontainers
@SpringBootTest(classes = MongoDbTestContainersApplication.class)
public abstract class AbstractBaseIntegrationTest {
@Container
static MongoDBContainer mongoDBContainer = new MongoDBContainer("mongo:7.0").withExposedPorts(27017);
@DynamicPropertySource
static void containersProperties(DynamicPropertyRegistry registry) {
mongoDBContainer.start();
registry.add("spring.data.mongodb.host", mongoDBContainer::getHost);
registry.add("spring.data.mongodb.port", mongoDBContainer::getFirstMappedPort);
}
}
We added the @Testcontainers annotation to enable Testcontainers support in our tests and the @SpringBootTest annotation to start the Spring Boot application context.
We also defined a MongoDB container field that starts the MongoDB container with the mongo:7.0 Docker image and exposes port 27017. The @Container annotation starts the MongoDB container before running the tests.
3.1. Data Access Layer Integration Tests
Now, we can write integration tests for our data access layer:
@Test
public void givenProductRepository_whenSaveAndRetrieveProduct_thenOK() {
Product product = new Product("Milk", "1L Milk", 10);
Product createdProduct = productRepository.save(product);
Optional<Product> optionalProduct = productRepository.findById(createdProduct.getId());
assertThat(optionalProduct.isPresent()).isTrue();
Product retrievedProduct = optionalProduct.get();
assertThat(retrievedProduct.getId()).isEqualTo(product.getId());
}
@Test
public void givenProductRepository_whenFindByName_thenOK() {
Product product = new Product("Apple", "Fruit", 10);
Product createdProduct = productRepository.save(product);
Optional<Product> optionalProduct = productRepository.findByName(createdProduct.getName());
assertThat(optionalProduct.isPresent()).isTrue();
Product retrievedProduct = optionalProduct.get();
assertThat(retrievedProduct.getId()).isEqualTo(product.getId());
}
We created two scenarios: the first saves and retrieves a product and the second finds a product by name. Both tests interact with the MongoDB database spun up by Testcontainers.
3.2. Application Integration Tests
Let’s create our application integration test class that extends the AbstractBaseIntegrationTest class:
@AutoConfigureMockMvc
public class ProductIntegrationTest extends AbstractBaseIntegrationTest {
@Autowired
private MockMvc mvc;
private ObjectMapper objectMapper = new ObjectMapper();
// ..
}
We need the @AutoConfigureMockMvc annotation to enable the MockMvc support in our tests and the MockMvc field to perform HTTP requests to our application.
Now, we can write integration tests for our application:
@Test
public void givenProduct_whenSave_thenGetProduct() throws Exception {
MvcResult mvcResult = mvc.perform(post("/products").contentType("application/json")
.content(objectMapper.writeValueAsString(new Product("Banana", "Fruit", 10))))
.andExpect(status().isOk())
.andReturn();
String productId = mvcResult.getResponse()
.getContentAsString();
mvc.perform(get("/products/" + productId))
.andExpect(status().isOk());
}
We developed a test to save a product and then retrieve it using HTTP. This process involves storing the data in a MongoDB database, which Testcontainers initializes.