코드
package com.fc.springprojectboard.repository;
import com.fc.springprojectboard.config.JpaConfig;
import com.fc.springprojectboard.domain.Article;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.context.annotation.Import;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@DisplayName("JPA 연결 테스트")
@Import(JpaConfig.class)
@DataJpaTest
class JpaRepositoryTest {
private final ArticleRepository articleRepository;
private final ArticleCommentRepository articleCommentRepository;
public JpaRepositoryTest(
@Autowired ArticleRepository articleRepository,
@Autowired ArticleCommentRepository articleCommentRepository
) {
this.articleRepository = articleRepository;
this.articleCommentRepository = articleCommentRepository;
}
@DisplayName("select 테스트")
@Test
void givenTestData_whenSelecting_thenWorksFine() {
// Given
// When
List<Article> articles = articleRepository.findAll();
// Then
assertThat(articles)
.isNotNull()
.hasSize(123);
}
@DisplayName("insert 테스트")
@Test
void givenTestData_whenInserting_thenWorksFine() {
// Given
long previousCount = articleRepository.count();
// When
Article savedArticle = articleRepository.save(Article.of("new article", "new content", "#spring"));
// Then
assertThat(articleRepository.count()).isEqualTo(previousCount + 1);
}
@DisplayName("update 테스트")
@Test
void givenTestData_whenUpdating_thenWorksFine() {
// Given
Article article = articleRepository.findById(1L).orElseThrow();
String updatedHashtag = "#springboot";
article.setHashtag(updatedHashtag);
// When
Article savedArticle = articleRepository.saveAndFlush(article);
// Then
assertThat(savedArticle).hasFieldOrPropertyWithValue("hashtag", updatedHashtag);
}
@DisplayName("delete 테스트")
@Test
void givenTestData_whenDeleting_thenWorksFine() {
// Given
Article article = articleRepository.findById(1L).orElseThrow();
long previousArticleCount = articleRepository.count();
long previousArticleCommentCount = articleCommentRepository.count();
int deletedCommentsSize = article.getArticleComments().size();
// When
articleRepository.delete(article);
// Then
assertThat(articleRepository.count()).isEqualTo(previousArticleCount - 1);
assertThat(articleCommentRepository.count()).isEqualTo(previousArticleCommentCount - deletedCommentsSize);
}
}
스프링 테스트 코드 심층 분석 (JPA 연결 테스트)
1. 테스트 클래스 선언 및 설정
@DisplayName("JPA 연결 테스트"): 이 애노테이션은 테스트 클래스에 대한 설명을 제공합니다. 이 경우 "JPA 연결 테스트"라는 명칭으로 테스트 케이스의 목적을 명확하게 표시합니다.
@Import(JpaConfig.class): 이 애노테이션은 테스트 시 사용할 JPA 설정 정보를 담고 있는
JpaConfig
클래스를 임포트하도록 지시합니다. 왜냐하면, 테이블의 필드중 생성일시, 수정일시, 생성자, 수정자라는 각 필드는 JPA Auditing 기능을 통해서 자동으로 데이터를 채워주게 된다. 이때 테스트 코드에서는 별도로 정의한 Config클래스를 Import해주어야 DB테스트시 객체 생성, 수정 시의 JPA Auditing이 잘 이루어지게 된다.@DataJpaTest: 이 애노테이션은 Spring Boot Data JPA 테스트를 위한 필수 요소입니다. 이를 통해 테스트를 위한 데이터베이스 연결, 엔티티 매핑, 트랜잭션 관리 등 필요한 JPA 관련 설정이 자동으로 구성됩니다. 개발자는 테스트 케이스에 집중할 수 있도록 환경 설정 부담을 줄여줍니다.
2. 의존성 주입
ArticleRepository: 이 필드는
@Autowired
애노테이션을 통해 의존성 주입됩니다.ArticleRepository
인터페이스는Article
엔티티와 관련된 데이터 접근 작업을 제공합니다. 테스트 케이스에서 데이터 조회, 저장, 수정, 삭제 등의 작업을 수행하기 위해 이 레포지토리 객체를 사용하게 됩니다.ArticleCommentRepository: 이 필드는
@Autowired
애노테이션을 통해 의존성 주입됩니다.ArticleCommentRepository
인터페이스는ArticleComment
엔티티와 관련된 데이터 접근 작업을 제공합니다. 테스트 케이스에서 댓글 데이터 조회, 저장, 수정, 삭제 등의 작업을 수행하기 위해 이 레포지토리 객체를 사용하게 됩니다.
스프링 테스트 코드 심층 분석
3. 테스트 메서드
- 3.2 테스트 메서드 예시 분석
3.2.3 givenTestData_whenUpdating_thenWorksFine(): 이 테스트 메서드는 테스트 데이터를 기반으로 데이터 업데이트 기능을 검증합니다.
- Given: 테스트 데이터를 생성하고 데이터베이스에 저장합니다. 업데이트할 엔티티를 선택하고, 업데이트 후 예상되는 값을 준비합니다.
- When:
articleRepository.saveAndFlush(updatedArticle)
메서드를 사용하여 업데이트된Article
엔티티를 저장합니다. - Then: 업데이트된 엔티티의 해당 필드 값이 예상되는 값과 일치하는지 확인합니다. 또한, 데이터베이스에 저장된 다른 엔티티의 데이터가 변경되지 않았는지 확인합니다.
3.2.4 givenTestData_whenDeleting_thenWorksFine(): 이 테스트 메서드는 테스트 데이터를 기반으로 데이터 삭제 기능을 검증합니다.
- Given: 테스트 데이터를 생성하고 데이터베이스에 저장합니다. 삭제할 엔티티를 선택하고, 삭제 후 예상되는 데이터베이스 상태를 준비합니다.
- When:
articleRepository.delete(article)
메서드를 사용하여 선택된Article
엔티티를 삭제합니다. - Then: 삭제된 엔티티가 데이터베이스에서 제거되었는지 확인합니다. 또한, 관련된 댓글 엔티티도 함께 삭제되었는지 확인합니다. 삭제 후 데이터베이스에 남아있는 엔티티의 개수가 예상되는 값과 일치하는지 확인합니다.
4. 테스트 결과
모든 테스트 메서드가 성공적으로 실행되면 테스트 케이스는 성공적으로 수행되었음을 의미합니다. 각 테스트 메서드의 assertThat
문장을 통해 검증 결과를 확인할 수 있습니다. 만약 테스트가 실패하면 오류 메시지가 출력되어 어떤 부분에서 문제가 발생했는지 파악할 수 있습니다.
5. 결론
이 코드는 Spring Boot와 JPA를 사용하여 데이터베이스와 상호작용하는 Repository 클래스의 테스트를 보여주는 좋은 예시입니다. 각 테스트 메서드는 "Given", "When", "Then" 구조를 사용하여 명확하게 작성되어 있으며, 테스트 케이스의 목적, 수행 과정, 결과 검증을 쉽게 이해할 수 있도록 구성되어 있습니다. 또한, assertThat
라이브러리를 사용하여 테스트 결과를 명확하게 검증하고 있습니다. 이러한 코드는 테스트 작성 및 코드 검증의 모범 사례를 보여주는 좋은 자료입니다.
6. 추가 고려 사항
- 테스트 데이터는 실제 데이터와 유사한 형태로 생성하는 것이 좋습니다.
- 테스트 케이스는 다양한 시나리오를 고려하여 작성해야 합니다.
- 테스트 케이스는 명확하고 간결하게 작성해야 합니다.
- 테스트 케이스는 정기적으로 실행해야 합니다.
핵심 요약
- Spring Boot Data JPA 테스트는 JPA를 사용하는 애플리케이션의 데이터 접근 계층을 테스트하는 데 유용한 도구입니다.
- "Given", "When", "Then" 구조는 테스트 케이스를 명확하게 작성하는 데 도움이 됩니다.
assertThat
라이브러리는 테스트 결과를 명확하게 검증하는 데 사용할 수 있습니다.- 테스트 케이스는 다양한 시나리오를 고려하여 작성해야 하며, 정기적으로 실행해야 합니다.
'프레임워크 > 자바 스프링' 카테고리의 다른 글
콘서트 예매 서비스에서 발생할 수 있는 동시성 이슈와 처리 (0) | 2024.07.20 |
---|---|
JPA 테스트 코드 작성시 UPDATE Query 생성이 안되네? (0) | 2024.05.28 |
[그냥 보는] application.yaml (0) | 2024.05.28 |
로깅 출력 어느 것으로?(feat.Interpolation vs Concatenation) (0) | 2024.04.22 |
findById vs getReferenceById 차이 (0) | 2024.04.22 |