In this tutorial, we will learn how to write Integration tests for Data Access or Repository layer using Testcontainers.
Let's first write Integration tests for StudentRepository
without using
Testcontainers and then later we will
use Testcontainers.
Let's create StudentRepositoryTests
class and add the following content to
it:
package net.javaguides.spirngboot.repository;
import net.javaguides.spirngboot.AbstractContainerBaseTest;
import net.javaguides.spirngboot.entity.Student;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import static org.junit.jupiter.api.Assertions.*;
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class StudentRepositoryTest {
@Autowired
private StudentRepository studentRepository;
// JUnit for save student operation - BDD style
@Test
public void givenStudentObject_whenSave_thenReturnSavedStudent(){
// given - setup or precondition
Student student = Student.builder().firstName("Ramesh")
.lastName("fadatare").email("ramesh@gmail.com").build();
// when - action or the testing
Student savedStudent = studentRepository.save(student);
// then - very output
Assertions.assertNotNull(savedStudent);
Assertions.assertNotNull(savedStudent.getId());
}
// JUnit for findById student operation - BDD style
@Test
public void givenStudentId_whenfindbyId_thenReturnSavedStudent(){
// given - setup or precondition
Student student = Student.builder().firstName("Ramesh")
.lastName("fadatare").email("ramesh@gmail.com").build();
Student savedStudent = studentRepository.save(student);
// when - action or the testing
Student studentDB = studentRepository.findById(student.getId()).get();
// then - very output
Assertions.assertNotNull(studentDB);
}
}
The Spring boot provides @DataJpaTest
annotation. This annotation will
disable full auto-configuration and
instead apply only configuration relevant to JPA tests. By default, it will use an embedded, in-memory H2
database instead of the one declared in the configuration file, for faster test running time as compared to
disk file database.
Note that we have disabled H2 in-memory database support using @AutoConfigureTestDatabase
annotation because
we want to run Integration tests with the MySQL database.
We have already configured the MySQL database in our Spring boot project so let's run Integration tests with the MySQL database.
A common problem when writing integration tests is the dependency on installed components (Ex: MySQL, RabbitMQ) where the integration tests are supposed to run.
In our case, our Integration tests depend on the MySQL database. Installing a specific version of the MySQL database in every machine where the integration tests are supposed to run takes a lot of time right.
Basically, our integration tests depend on external services (installing MySQL, Rabbit MQ, Redis, etc) to run the integration tests right then how to reduce this dependency - what will be the solution.
The solution is Testcontainers.
Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.
Testcontainer allows us to use Docker containers within our tests. As a result, we can write self-contained integration tests that depend on external resources.
Let's change the Integration test to use Testcontainers.
We just need to extend our StudentRepositoryTest
class with AbstractContainerBaseTest
class:
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class StudentRepositoryTest extends AbstractContainerBaseTest {
// code goes here
}
Here is the complete code:
package net.javaguides.spirngboot.repository;
import net.javaguides.spirngboot.AbstractContainerBaseTest;
import net.javaguides.spirngboot.entity.Student;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import static org.junit.jupiter.api.Assertions.*;
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class StudentRepositoryTest extends AbstractContainerBaseTest {
@Autowired
private StudentRepository studentRepository;
// JUnit for save student operation - BDD style
@Test
public void givenStudentObject_whenSave_thenReturnSavedStudent(){
// given - setup or precondition
Student student = Student.builder().firstName("Ramesh")
.lastName("fadatare").email("ramesh@gmail.com").build();
// when - action or the testing
Student savedStudent = studentRepository.save(student);
// then - very output
Assertions.assertNotNull(savedStudent);
Assertions.assertNotNull(savedStudent.getId());
}
// JUnit for save student operation - BDD style
@Test
public void givenStudentId_whenfindbyId_thenReturnSavedStudent(){
// given - setup or precondition
Student student = Student.builder().firstName("Ramesh")
.lastName("fadatare").email("ramesh@gmail.com").build();
Student savedStudent = studentRepository.save(student);
// when - action or the testing
Student studentDB = studentRepository.findById(student.getId()).get();
// then - very output
Assertions.assertNotNull(studentDB);
}
}
In this tutorial, we have discussed how to perform Spring Boot Data Access or Repository layer Integration testing using Testcontainers.