토이 프로젝트를 하는 동안 간단한 기능을 하나 추가해서 테스트 코드를 작성했다.
테스트 코드를 작성하면서 앞으로 많이 사용해볼 내용을 따로 정리하는 취지의 글입니다.
(개인의견, 부족한점, 조언, 충고 등등 많은 채찍을 기다립니다!)
추가한 기능은 "특정 상품리뷰가 특정 사용자가 작성한 것인지 확인" 하는 기능이었다.
상품리뷰를 저장하는 entity 가 있었고, userId 를 parameter로 받아 equals를 하는 아주 간단한 기능이다.
@Entity
public class ProductReview {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private LocalDateTime writeDate;
@Lob
private String content;
private int score;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "product_id")
private Product product;
@Column(name = "user_id")
private Long userId;
public ProductReview(String content, int score) {
this.writeDate = LocalDateTime.now();
this.content = content;
this.score = score;
}
@Builder
public ProductReview(String content, int score, Product product, Long userId) {
this(content, score);
byUser(userId);
byProduct(product);
}
public ProductReview byUser(@NotNull Long userId) {
this.userId = userId;
return this;
}
public ProductReview byProduct(@NotNull Product product) {
this.product = product;
product.addReview(this);
return this;
}
/* == 코드 중략 == */
// 사용자가 작성한 리뷰인지 확인
public boolean isWriter(Long userId) {
return Objects.equals(this.userId, userId);
}
}
해당 메서드를 테스트 하기 위해 테스트 코드를 아래와 같이 작성했다.
@Test
@DisplayName("상품 리뷰를 작성한 사용자가 맞는지 틀린지 확인")
void is_writer_test_success() {
// given
Product product = new Product("상품 1", 12000, 20, new Category("상위 카테고리"), new Category("하위 카테고리"));
ProductReview productReview = new ProductReview("리뷰 등록 합니다.", 3, product, 1L);
// when
boolean isWriter = productReview.isWriter(1L);
// then
Assertions.assertThat(isWriter).isTrue();
}
결과는 당연히 테스트 성공으로 나왔고, 실패 케이스도 검증하기 위해 아래와 같이 만들었다.
@Test
@DisplayName("상품 리뷰를 작성한 사용자가 맞는지 틀린지 확인 - 틀린 경우")
void is_writer_test_fail() {
// given
Product product = new Product("상품 1", 12000, 20, new Category("상위 카테고리"), new Category("하위 카테고리"));
ProductReview productReview = new ProductReview("리뷰 등록 합니다.", 3, product, 1L);
// when
boolean isWriter = productReview.isWriter(2L);
// then
Assertions.assertThat(isWriter).isFalse();
}
위 테스트도 isFalse 검증이기에 당연히 성공으로 결과가 확인됐다.
작성하고 나니, 뭔가 복붙해서 값만 바꿔서 만든 또 하나의 테스트코드라는게 별로였다.
그래서 우아한테크캠프 Pro 5기를 통해 알게된 @CsvSource 를 써보기로 했다.
@ParameterizedTest
@CsvSource(value = {"1L:true","2L:false","3L:false"}, delimiterString = ":")
@DisplayName("상품 리뷰를 작성한 사용자가 맞는지 틀린지 확인")
void is_writer_test(Long userId, boolean result) {
// given
Product product = new Product("상품 1", 12000, 20, new Category("상위 카테고리"), new Category("하위 카테고리"));
ProductReview productReview = new ProductReview("리뷰 등록 합니다.", 3, product, 1L);
// when
boolean isWriter = productReview.isWriter(userId);
// then
assertThat(isWriter).isEqualTo(result);
}
먼저, @CsvSource 를 쓰기 전에, @ParameterizedTest 라는 annotation을 먼저 정의해야 한다.
해당 annotation을 사용하게 되면, 특정 데이터를 테스트 케이스의 parameter로 받아서 테스트 코드에 사용할 수 있게 된다.
위에서 언급한 "특정 데이터" 에도 여러 가지가 존재하는데 그 중에서 @CsvSource 를 사용해 보았다.
CSV 는 Comma Seperated Values 의 약자로, 쉼표로 값들을 구분해서 저장하는 데이터 포멧을 의미한다.(주로 스프레드 시트에서 사용된다.)
@CsvSource 에서 value 와 delimeiterString 속성을 사용해서, 실제로 테스트 케이스에 파라미터로 어떤 값을 받을 건지 정할 수 있다.
위 코드를 예로 설명해 보자면 다음과 같다.
- value 의 큰 따옴표 묶음 만큼 테스트 코드를 실행한다. => 1L:true, 2L:false, 3L:false 순으로 3번의 테스트 코드를 실행한다.
- 각 테스트 케이스는 delimiterString(:) 에 선언된 문자로 구분된 결과를 파라미터로 사용한다. => 1L:true 의 경우, 1L과 true 2개의 파라미터로 분리되어 사용된다.
이제 위 테스트 코드를 실행하면 아래와 같은 에러가 발생한다.
첫 줄의 로그를 보면 아래와 같다.
org.junit.jupiter.api.extension.ParameterResolutionException: Error converting parameter at index 0: Failed to convert String "1L" to type java.lang.Long
해석해보면, 파라미터로 넘어온 1L은 String 이라 Long 으로 변환할 수 없다는 의미이다.
Java 에서 Long 타입은 뒤에 L 을 붙여야 해서 붙인건데, @CsvSource 에서 파싱될 떄, L 이라는 문자가 존재해서 1L 자체를 문자로 인식하는 것 같다.
그래서 아래와 같이 L을 모두 떼어봤다.
@ParameterizedTest
@CsvSource(value = {"1:true","2:false","3:false"}, delimiterString = ":")
@DisplayName("상품 리뷰를 작성한 사용자가 맞는지 틀린지 확인")
void is_writer_test(Long userId, boolean result) {
// given
Product product = new Product("상품 1", 12000, 20, new Category("상위 카테고리"), new Category("하위 카테고리"));
ProductReview productReview = new ProductReview("리뷰 등록 합니다.", 3, product, 1L);
// when
boolean isWriter = productReview.isWriter(userId);
// then
assertThat(isWriter).isEqualTo(result);
}
그랬더니 아래와 같이 테스트가 성공한 것을 확인할 수 있었다.
'Test Code' 카테고리의 다른 글
[Spring MVC] @WebMvcTest 에서 Multipart 테스트 하기. (0) | 2023.09.22 |
---|---|
[ATDD] RestAssured를 이용해 multipart/form-data 요청 테스트 시, 한글 깨지는 오류 해결하기 (0) | 2023.04.22 |
댓글