In this post, we’ll learn how to implement Embedded MongoDB for Spring Boot Integration testing.
· Prerequisites
· Overview
∘ Key Features of Embedded MongoDB
· Usage with Spring Boot
∘ Maven Dependencies
∘ Application Properties
∘ Writing Testing
· Conclusion
· References
Prerequisites
This is the list of all the prerequisites:
- Spring Boot 3+
- Maven 3.6.3
- Java 21
Overview
An embedded database can help test the application’s data layer without needing an external database server or container instance. It can also provide a fast and isolated testing environment for integration testing.
Embedded MongoDB refers to using an in-memory or embedded version of MongoDB for testing and development purposes. This allows developers to run MongoDB without needing a separate server, making it easier to set up and tear down test environments.
The most commonly used library for this purpose in Java applications is Flapdoodle’s embedded MongoDB.
Key Features of Embedded MongoDB
- In-Memory Database: It runs in memory, which makes it fast and suitable for testing.
- Isolation: Each test can run in an isolated environment, ensuring that tests do not interfere.
- No External Dependencies: You do not need to install or configure a separate MongoDB server, simplifying the development and testing process.
- Easy Setup: It can be easily integrated into your existing test framework.
Usage with Spring Boot
Here is a simple project structure of a typical Spring Boot REST API with MongoDB.

Maven Dependencies
To use Embedded Mongo with MongoDB in Spring Boot 3.x, we need to add the Flapdoodle’s dependency to our pom.xml file with test scope:
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo.spring3x</artifactId>
<version>4.18.0</version>
<scope>test</scope>
</dependency>
The official Flapdoodle GitHub provides dependencies for Spring Boot 2.x.
Application Properties
Next, we need to add some built-in property configurations in the application properties file to tell Spring Boot to use the built-in MongoDB instance instead of a separate MongoDB server.
de.flapdoodle.mongodb.embedded.version=7.0.0
de.flapdoodle.mongodb.embedded.version: Specifies the version of the embedded MongoDB instance we want to use. Make sure to choose a version that is compatible with the application.
Spring Boot will automatically try to download this version and start the embedded MongoDB when running tests.
Writing Testing
- Repository integration testing
Let’s write unit tests to verify the functionality of the BookRepository.
@Repository
public interface BookRepository extends MongoRepository<Book, String> {
}
@DataMongoTest
class BookRepositoryIT {
@Autowired
private BookRepository repository;
private Book book;
@BeforeEach
public void initTest() {
repository.deleteAll();
book = Book.builder()
.title("title")
.isbn("20351LOPf")
.page(100)
.price(250)
.description("my description")
.build();
}
@Test
void testFindById() {
var bookCreated = repository.save(book);
Optional<Book> bookOptional = repository.findById(bookCreated.getId());
assertThat(bookOptional).hasValueSatisfying(bookData -> {
assertThat(bookData.getId()).isNotNull();
assertThat(bookData.getDescription()).isEqualTo(book.getDescription());
assertThat(bookData.getIsbn()).isEqualTo(book.getIsbn());
assertThat(bookData.getPage()).isEqualTo(book.getPage());
assertThat(bookData.getPrice()).isEqualTo(book.getPrice());
assertThat(bookData.getTitle()).isEqualTo(book.getTitle());
});
}
@Test
void testFindAll() {
repository.save(book);
assertThat(repository.findAll())
.isNotEmpty()
.hasSize(1)
.extracting(Book::getTitle)
.contains(book.getTitle());
}
@Test
void testSave() {
var bookCreated = repository.save(book);
assertThat(bookCreated.getId()).isNotNull();
assertThat(bookCreated.getDescription()).isEqualTo(book.getDescription());
assertThat(bookCreated.getIsbn()).isEqualTo(book.getIsbn());
assertThat(bookCreated.getPage()).isEqualTo(book.getPage());
assertThat(bookCreated.getPrice()).isEqualTo(book.getPrice());
assertThat(bookCreated.getTitle()).isEqualTo(book.getTitle());
}
}
- Controller integration testing
@Slf4j
@RestController
@RequestMapping("/api/book")
public class BookController {
private final BookService entityService;
public BookController(BookService entityService) {
this.entityService = entityService;
}
/**
* {@code POST /book} : Create a new book.
*
* @param book the book to create.
* @return the {@link ResponseEntity} with status {@code 201 (Created)} and with body the new book.
*/
@PostMapping()
public ResponseEntity<Book> createBook(@RequestBody @Valid Book book) {
log.debug("REST request to save Book : {}", book);
return new ResponseEntity<>(entityService.create(book), HttpStatus.CREATED);
}
/**
* {@code PUT /book/:id} : Updates an existing book.
*
* @param book the book to update.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the updated book,
* or with status {@code 400 (Bad Request)} if the book is not valid,
* or with status {@code 500 (Internal Server Error)} if the book couldn't be updated.
*/
@PutMapping(value = "/{id}")
public ResponseEntity<Book> updateBook(@Valid @RequestBody Book book, @PathVariable("id") String id) {
log.debug("REST request to update Book : {}", book);
Book result = entityService.update(book, id);
return ResponseEntity.ok().body(result);
}
/**
* {@code GET /book} : get all the books.
*
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and the list of book in body.
*/
@GetMapping()
public ResponseEntity<List<Book>> getAllBook() {
log.debug("REST request to get all books");
List<Book> lst = entityService.getAll();
return new ResponseEntity<>(lst, HttpStatus.OK);
}
/**
* {@code GET /book/:id} : get the "id" book.
*
* @param id the id of the book to retrieve.
* @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the book, or with status {@code 404 (Not Found)}.
*/
@GetMapping(value = "/{id}")
public ResponseEntity<Book> getOneBook(@PathVariable("id") String id) {
log.debug("REST request to get Book : {}", id);
Book e = entityService.getOne(id);
return new ResponseEntity<>(e, HttpStatus.OK);
}
/**
* {@code DELETE /book/:id} : delete the "id" book.
*
* @param id the id of the book to delete.
* @return the {@link ResponseEntity} with status {@code 204 (NO_CONTENT)}.
*/
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteBook(@PathVariable("id") String id) {
log.debug("REST request to delete Book : {}", id);
entityService.delete(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
}
@SpringBootTest
@AutoConfigureMockMvc
class BookControllerIT {
@Autowired
private BookRepository repository;
@Autowired
private MockMvc mockMvc;
private static final String BASE_CONTROLLER_ENDPOINT = "/api/book";
private Book book;
@BeforeEach
public void initTest() {
repository.deleteAll();
book = Book.builder()
.title("testing")
.isbn("20351LOPf")
.page(110)
.price(214)
.description("controller IT")
.build();
}
@Test
void createBook() throws Exception {
int databaseSizeBeforeCreate = repository.findAll().size();
mockMvc
.perform(post(BASE_CONTROLLER_ENDPOINT).contentType(MediaType.APPLICATION_JSON)
.content(TestUtil.convertObjectToJsonBytes(book)))
.andExpect(status().isCreated());
var books = repository.findAll();
assertThat(books).hasSize(databaseSizeBeforeCreate + 1);
Optional<Book> bookOptional = books.stream().filter(b -> b.getIsbn().equals("20351LOPf")).findFirst();
assertThat(bookOptional).hasValueSatisfying(testBook -> {
assertThat(testBook.getId()).isNotNull();
assertThat(testBook.getDescription()).isEqualTo("controller IT");
assertThat(testBook.getIsbn()).isEqualTo("20351LOPf");
assertThat(testBook.getPage()).isEqualTo(110);
assertThat(testBook.getPrice()).isEqualTo(214);
assertThat(testBook.getTitle()).isEqualTo("testing");
});
}
@Test
void updateBook() throws Exception {
repository.save(book);
int databaseSizeBeforeUpdate = repository.findAll().size();
book.setTitle("update title");
book.setIsbn("00125689");
book.setPage(50);
mockMvc
.perform(put(MessageFormat.format("{0}/{1}", BASE_CONTROLLER_ENDPOINT, book.getId())).contentType(MediaType.APPLICATION_JSON)
.content(TestUtil.convertObjectToJsonBytes(book)))
.andExpect(status().isOk());
var books = repository.findAll();
assertThat(books).hasSize(databaseSizeBeforeUpdate);
Optional<Book> bookOptional = books.stream().filter(b -> b.getIsbn().equals("00125689")).findFirst();
assertThat(bookOptional).hasValueSatisfying(testBook -> {
assertThat(testBook.getId()).isNotNull();
assertThat(testBook.getDescription()).isEqualTo("controller IT");
assertThat(testBook.getIsbn()).isEqualTo("00125689");
assertThat(testBook.getPage()).isEqualTo(50);
assertThat(testBook.getPrice()).isEqualTo(214);
assertThat(testBook.getTitle()).isEqualTo("update title");
});
}
@Test
void getAllBook() throws Exception {
repository.save(book);
mockMvc.perform(get(BASE_CONTROLLER_ENDPOINT)
.accept(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.jsonPath("$.[*]").exists())
.andExpect(MockMvcResultMatchers.jsonPath("$.[*].title").isNotEmpty())
.andExpect(MockMvcResultMatchers.jsonPath("$.[*].isbn").value(book.getIsbn()));
}
@Test
void getOneBook() throws Exception {
repository.save(book);
mockMvc.perform(get(MessageFormat.format("{0}/{1}", BASE_CONTROLLER_ENDPOINT, book.getId()))
.accept(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.jsonPath("$.id").exists())
.andExpect(MockMvcResultMatchers.jsonPath("$.isbn").value(book.getIsbn()))
.andExpect(MockMvcResultMatchers.jsonPath("$.description").value(book.getDescription()))
.andExpect(MockMvcResultMatchers.jsonPath("$.page").value(book.getPage()));
}
@Test
void getOneBookNotFound() throws Exception {
mockMvc.perform(get(MessageFormat.format("{0}/1", BASE_CONTROLLER_ENDPOINT))
.accept(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isBadRequest());
}
@Test
void deleteBook() throws Exception {
repository.save(book);
mockMvc.perform(delete(MessageFormat.format("{0}/{1}", BASE_CONTROLLER_ENDPOINT, book.getId()))
.accept(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isNoContent());
}
}
Conclusion
Well done !!. In this post, we learned to write integration tests using Embedded MongoDB for Spring Boot Integration testing.
The complete source code is available on GitHub.
Support me through GitHub Sponsors.
Thank you for reading !! See you in the next post.