@DataJpaTest
@DataJpaTest 어노테이션은 JPA관련 테스트 설정만 로드합니다.
DataSource의 설정이 정상적인지, JPA를 이용하여 데이터를 저장, 수정, 삭제하는지 등의 테스트가 가능하며, 내장형 데이터베이스를 사용하여 실제 데이터베이스를 사용하지 않고 테스트 데이터베이스로 테스트가 가능합니다.
(H2, DERBY, HSQLDB)
테스트코드 작성
- SpringBoot 3.3.3
- Java21
- Junit5
- Spring Data JPA
- 테스트코드 환경 구축
Entity
@Entity
@Getter
@NoArgsConstructor
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String title;
private String content;
private Board(String title, String content) {
this.title = title;
this.content = content;
}
public static Board create(String title, String content) {
return new Board(title, content);
}
}
Test 코드에서 값을 받아올 생성자를 추가하였습니다.
Repository
public interface BoardRepository extends JpaRepository<Board, Long> {
}
Test를 위한 application.yml
server:
port: 80
spring:
datasource:
url: jdbc:h2:~/test
username: sa
password:
driver-class-name: org.h2.Driver
jpa:
hibernate:
ddl-auto: create
properties:
hibernate:
show_sql: true
format_sql: true
logging:
level:
org:
hibernate:
sql: debug
type:
descriptor:
sql:
BasicBinder: trace
@DataJapTest를 이용한 Test시 yml파일에 사용 데이터베이스를 직접 입력하지 않고
testRuntimeOnly 'com.h2database:h2'
라이브러리만 build.gradle에 추가해도 무관합니다.
(필자는 Test를 위한 yml 설정을 어떻게 하였는지 직관적으로 확인하기 위해 작성)
main/resources 아래 application.yml
test/resources 아래 application.yml
이렇게 구분 지어 생성하면 각 main실행, test실행별로 application.yml을 나누어 적용이 가능해집니다.
- Test 코드
@DataJpaTest
class BoardRepositoryTest {
@Autowired
private BoardRepository boardRepository;
@AfterEach
public void clear() {
boardRepository.deleteAllInBatch(); // 1
}
@Test
@DisplayName("board에 저장한 값을 조회할 수 있다")
public void saveTest() {
// given
// title, content 내용을 매개변수로 전달
Board board = Board.create("todo-list", "hello");
// when
// 매개변수로 전달된 내용 save
boardRepository.save(board);
// save가 되었는지 확인하기 위한 조회
Board findBoard = boardRepository.findAll().stream().findAny().orElseThrow();
// then
// 조회된 값과 저장된 값이 동일한지 확인
Assertions.assertThat(findBoard.getTitle()).isEqualTo(board.getTitle());
Assertions.assertThat(findBoard.getContent()).isEqualTo(board.getContent());
}
}
1. 테스트 실행 후 JPA 데이터 삭제
deletAll이 아닌 deletAllInBatch 사용 이유 :
// deleteAll을 사용하였을 경우 동작 쿼리를 확인하기 위한 임시 Test 코드
@Autowired
private BoardRpository boardRepository;
@Test
public void deleteAll() {
// given
Board board1 = Board.create("title1", "content1");
Board board2 = Board.create("title2", "content2");
Board board3 = Board.create("title3", "content3");
// when
boardRepository.save(board1);
boardRepository.save(board2);
boardRepository.save(board3);
// then
boardRepository.deleteAll();
}
deletAll를 이용하여 Test실행 결과 JPA데이터 삭제를 하기 위해 조회 후 각 PK별로 delete 쿼리가 동작하여 처리되는 것을 확인할 수 있습니다.
// deleteAllInBatch를 사용하였을 경우 동작 쿼리를 확인하기 위한 임시 Test 코드
@Autowired
private BoardRpository boardRepository;
@Test
public void deleteAll() {
// given
Board board1 = Board.create("title1", "content1");
Board board2 = Board.create("title2", "content2");
Board board3 = Board.create("title3", "content3");
// when
boardRepository.save(board1);
boardRepository.save(board2);
boardRepository.save(board3);
// then
boardRepository.deleteAllInBatch(); // deleteAll -> deleteAllInBatch 변경
}
deletAllInBatch를 이용하여 Test실행 결과 JPA데이터 삭제 시 한 번의 delete 쿼리가 동작하여 처리되는 것을 확인할 수 있습니다.
Test시 각 PK별로 delete쿼리를 동작하기보다 한 번에 처리하여 불필요한 데이터사용을 막을 수 있기 때문에 deletAll이 아닌 deletAllInBatch를 사용하였습니다.
'Spring' 카테고리의 다른 글
[Spring] Redis를 사용한Session 로그인 구현, Security없이 인증, 인가 구현 (26) | 2024.11.14 |
---|---|
[Spring] offset, no offset 차이점과 페이지네이션 구현예제 (6) | 2024.10.23 |
[Spring] RequestBody, Response의 값이 null 일 때, JSON의 직렬화 역직렬화 (0) | 2024.10.10 |
[Spring]@DataJpaTest, @SpringBootTest 차이 (2) | 2024.08.28 |
[Spring] Spring IOC, DI, DL 이란? (0) | 2024.07.27 |