킹의 개발일지
JUnit, Mockito 및 MockMvc를 사용한 스프링 부트 단위 테스트(5) 본문
Test SpringBoot MVC Web Apps - Database Integration Testing
#시나리오
주어진 시나리오로, 새로 일하게된 직장에서 이전 직원이 데이터 베이스 작업을 하던도중 일을 그만두는 바람에 내가 작업해야 한다는것이다.
해야할 작업
- H2 인메모리 DB에 데이터를 저장하는 기능을 완성해야한다. 종속은 미리 pom.xml에 추가해두었다.
- 그에 대한 단위 테스트와 통합 테스트를 추가해야한다.
- 일반적으로 DB를 연결해서 테스트를 진행하면 그것을 통합테스트라고 한다.
- 네번 째 포스팅에서 봤던 작업은 Mocking을 이용해서 서비스 레이어에서 메서드를 특정 메서드를 호출하면 Dao 객체가 특정한 값을 반환하도록 했었다.
- 이제는 실제 DB에 값을 읽고 쓰는 테스트를 작성해야한다.
TDD를 사용해 Service레이어와 DAO를 빌드하자.
주어진 작업을 TDD를 이용해서 완수하고자 한다.
첫번째로 실패하는 테스트 케이스를 작성해보자. 당연히 해당 클래스를 만들지 않았기에 멤버 함수를 호출 했을 때 빨간불이 들어오는건 당연하다!

테스트를 실행하면 빨간 불을 내며 당연히 실패한다!

실패하는 테스트를 작성했으면 이젠 테스트에 필요한 StudentAndGradeService 클래스를 만들 차례이다.
@Service
@Transactional
public class StudentAndGradeService {
private StudentDao studentDao;
@Autowired
public void setStudentDao(StudentDao studentDao) {
this.studentDao = studentDao;
}
public void createStudent(String firstName, String lastName, String emailAddress){
CollegeStudent collegeStudent = new CollegeStudent(firstName,lastName,emailAddress);
collegeStudent.setId(0);
studentDao.save(collegeStudent);
}
}
그리고 StudentAndGradeService 클래스는 StudentDao에 의존하고 있기 때문에,
다음으로 Spring Data Jpa 를 사용해서 StudentDao를 만들어주어야 한다.
아래와 같이 다 만들어주면 테스트의 빨간불은 없어지고 테스트 실행시 통과할 것이다.
즉, 테스트에서 데이터베이스에 값을 읽고 쓸 수 있게 됐다.
@Repository
public interface StudentDao extends JpaRepository<CollegeStudent, Integer> {
CollegeStudent findByEmailAddress(String studentEmail);
}

이후 서비스 레이어에 추가 메서드를 넣어주고 여러 테스트를 진행해 봤다.
@TestPropertySource("classpath:application.properties")
@SpringBootTest
public class StudentAndGradeServiceTest {
@Autowired
private StudentAndGradeService studentService;
@Autowired
private StudentDao studentDao;
@Autowired
private JdbcTemplate jdbcTemplate;
@BeforeEach
public void setupDatabase() {
jdbcTemplate.execute("INSERT INTO Student(id, firstname, lastname, email_address) " +
"values (1, 'Juhong', 'An', 'test@test.com')");
}
@AfterEach
public void deleteDatabase() {
jdbcTemplate.execute("DELETE FROM Student ");
}
@Test
public void createStudentService() {
studentService.createStudent("Juhong", "An", "wednesday5028@gmail.com");
CollegeStudent student = studentDao.findByEmailAddress("wednesday5028@gmail.com");
System.out.println(student);
assertEquals("wednesday5028@gmail.com", student.getEmailAddress(), "Find by email");
}
@Test
public void deleteStudentService() {
Optional<CollegeStudent> deletedCollegeStudent = studentDao.findById(1);
assertTrue(deletedCollegeStudent.isPresent(), "Return true");
studentService.deleteStudent(1);
deletedCollegeStudent = studentDao.findById(1);
assertFalse(deletedCollegeStudent.isPresent(), "Return false");
}
@Test
public void isStudentNullCheck() {
assertTrue(studentService.checkIfStudentIsNullById(1));
assertFalse(studentService.checkIfStudentIsNullById(0));
}
@Sql("classpath:insertData.sql")
@Test
public void getGradebookService() {
Iterable<CollegeStudent> iterableCollegeStudents = studentService.getGradebook();
List<CollegeStudent> collegeStudents = new ArrayList<>();
iterableCollegeStudents.forEach((collegeStudents::add));
assertEquals(5, collegeStudents.size());
}
}
여기서 궁금한점 하나가 생기는데
application.properties에는 datasources 정보를 전부 주석처리 해두었다.
info.school.name=luv2code
info.app.name=My Super Cool Gradebook
info.app.description=a fun way to track student grades!
info.app.version=1.0.0
## Server Properties
server.port= 1500
## H2 Test Database creds
#spring.datasource.url=jdbc:h2:mem:testdb
#spring.datasource.driverClassName=org.h2.Driver
#spring.datasource.username=sa
#spring.datasource.password=password
#spring.datasource.initialization-mode=always
#spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
#spring.h2.console.enabled=true
#spring.jpa.hibernate.ddl-auto=create-drop
#spring.jpa.show-sql = true
그럼 DB 커넥션은 어떻게 되는것일까!
스프링부트에서는, 만약 임베디드 데이터베이스가 pom.xml에 종속에 포함되면,
스프링 부트가 자동으로 DB커넥션을 구성해준다.
지금 프로젝트는 H2 데이터베이스를 종속성으로 추가했으며 스프링 부트가 임베디드 H2 데이터베이스에 자동으로 구성한다.
따라서 DB커넥션 없이도 일반 데이터베이스처럼 사용할 수 있다.
데이터 시드
서비스 레이어를 통합테스트 하다보면 테스트에 사용될 데이터들이 많이 필요하다.
그러나 일일이 SQL문을 나열하면 타이포도 일어나기 쉽고 원치 않는 결과가 나올수 도 있다.
때문에 리소스 디렉토리 아래에 sql 파일을 생성해두면 테스트에서 해당 sql을 사용할 수 있다.
먼저 resorces 디렉토리 아래에 insertData.sql 파일을 생성하고 insert문을 작성한다.
insert into student(id, firstname, lastname, email_address) values (11, 'Student', 'One', 'student.one@test.com')
insert into student(id, firstname, lastname, email_address) values (12, 'Student', 'Two', 'student.two@test.com')
insert into student(id, firstname, lastname, email_address) values (13, 'Student', 'Three', 'student.three@test.com')
insert into student(id, firstname, lastname, email_address) values (14, 'Student', 'Four', 'student.four@test.com')
그리고 테스트 데이터가 필요한 테스트에 @Sql(”classpath:insertData.sql”) 어노테이션을 붙혀준다.
참고로 @BeforeEach 가 먼저 실행되고 @Sql이 실행된다.
@Sql("classpath:insertData.sql")
@Test
public void getGradebookService() {
Iterable<CollegeStudent> iterableCollegeStudents = studentService.getGradebook();
List<CollegeStudent> collegeStudents = new ArrayList<>();
iterableCollegeStudents.forEach((collegeStudents::add));
assertEquals(5, collegeStudents.size());
}
'Junit' 카테고리의 다른 글
| JUnit, Mockito 및 MockMvc를 사용한 스프링 부트 단위 테스트(4) (0) | 2022.06.16 |
|---|---|
| JUnit, Mockito 및 MockMvc를 사용한 스프링 부트 단위 테스트(3) (0) | 2022.06.16 |
| JUnit, Mockito 및 MockMvc를 사용한 스프링 부트 단위 테스트(2) (0) | 2022.06.10 |
| JUnit, Mockito 및 MockMvc를 사용한 스프링 부트 단위 테스트(1) (0) | 2022.06.03 |
| JUnit, Mockito 및 MockMvc를 사용한 스프링 부트 단위 테스트 (0) | 2022.06.01 |