인프런 커뮤니티 질문&답변

모깅님의 프로필 이미지
모깅

작성한 질문수

스프링 DB 2편 - 데이터 접근 활용 기술

테스트 - @Transactional

@Transactional 롤백,,?

해결된 질문

작성

·

355

·

수정됨

0

안녕하세요 강사님. 프로젝트 진행중에 간단한 테스트 작업 중 이상한 결과가 나와서 질문드립니다..!

@Transactional
@SpringBootTest
@ActiveProfiles("test")
class ProductListResponseDtoTest {

    @Autowired ProductRepository productRepository;

    @Test
    @DisplayName("주문 상세가 주어졌을 때 ProductListResponseDto 변환")
    public void ofWithOrderDetail() {
        Product product = Product.builder()
                .price(1000L)
                .name("빵빵이")
                .productNo("123")
                .build();
        productRepository.save(product);

        OrderDetail orderDetail = OrderDetail.builder()
                .product(product)
                .price(product.getPrice())
                .quantity(2L)
                .build();

        // when
        ProductListResponseDto result = ProductListResponseDto.of(orderDetail);

        // then
        assertThat(result).extracting("productId", "productNo", "name", "price", "quantity")
                .contains(1L, "123", "빵빵이", 1000L, 2L);
    }


    @Test
    @DisplayName("상품과 수량이 주어졌을 때 ProductListResponseDto 변환")
    public void ofWithProductAndQuantity() {
        Long quantity = 2L;

        Product product = Product.builder()
                .price(1000L)
                .name("빵빵이")
                .productNo("123")
                .build();
        productRepository.save(product);

        // when
        ProductListResponseDto result = ProductListResponseDto.of(product, quantity);

        // then
        assertThat(result).extracting("productId", "productNo", "name", "price", "quantity")
                .contains(1L, "123", "빵빵이", 1000L, 2L);

    }

}

@Transactional를 통해 각 테스트가 롤백되어 productId가 모두 1L 될 것으로 예상하였습니다.

그런데 기대와 달리 실패를 하였는데요. 첫번째 테스트(ofWithOrderDetail)의 productId의 값이 2L 되었습니다.

 

insert문과 에러 메세지입니다.

Hibernate: 
    insert 
    into
        product
        (category_id, created_at, deleted_at, discount_rate, is_own, is_subs, name, price, product_no, stock, thumb_img, updated_at, product_id) 
    values
        (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, default)
2024-01-29T22:28:07.219+09:00  INFO 3636 --- [           main] p6spy                                    : #1706534887219 | took 4ms | statement | connection 3| url jdbc:h2:mem:~/Marketbridge
insert into product (category_id,created_at,deleted_at,discount_rate,is_own,is_subs,name,price,product_no,stock,thumb_img,updated_at,product_id) values (?,?,?,?,?,?,?,?,?,?,?,?,default)
insert into product (category_id,created_at,deleted_at,discount_rate,is_own,is_subs,name,price,product_no,stock,thumb_img,updated_at,product_id) values (NULL,NULL,NULL,NULL,NULL,NULL,'빵빵이',1000,'123',NULL,NULL,NULL,default);
2024-01-29T22:28:07.299+09:00  INFO 3636 --- [           main] p6spy                                    : #1706534887299 | took 0ms | rollback | connection 3| url jdbc:h2:mem:~/Marketbridge

;
Hibernate: 
    insert 
    into
        product
        (category_id, created_at, deleted_at, discount_rate, is_own, is_subs, name, price, product_no, stock, thumb_img, updated_at, product_id) 
    values
        (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, default)
2024-01-29T22:28:07.309+09:00  INFO 3636 --- [           main] p6spy                                    : #1706534887309 | took 0ms | statement | connection 4| url jdbc:h2:mem:~/Marketbridge
insert into product (category_id,created_at,deleted_at,discount_rate,is_own,is_subs,name,price,product_no,stock,thumb_img,updated_at,product_id) values (?,?,?,?,?,?,?,?,?,?,?,?,default)
insert into product (category_id,created_at,deleted_at,discount_rate,is_own,is_subs,name,price,product_no,stock,thumb_img,updated_at,product_id) values (NULL,NULL,NULL,NULL,NULL,NULL,'빵빵이',1000,'123',NULL,NULL,NULL,default);
2024-01-29T22:28:07.317+09:00  INFO 3636 --- [           main] p6spy                                    : #1706534887317 | took 0ms | rollback | connection 4| url jdbc:h2:mem:~/Marketbridge

;

java.lang.AssertionError: [Extracted: productId, productNo, name, price, quantity] 
Expecting ArrayList:
  [2L, "123", "빵빵이", 1000L, 2L]
to contain:
  [1L, "123", "빵빵이", 1000L, 2L]
but could not find the following element(s):
  [1L]


	at com.objects.marketbridge.order.service.dto.ProductListResponseDtoTest.ofWithOrderDetail(ProductListResponseDtoTest.java:44)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)

 

of 메서드 입니다.

@Getter
public class ProductListResponseDto {

    private Long productId;
    private String productNo;
    private String name;
    private Long price;
    private Long quantity;

    @Builder
    private ProductListResponseDto(Long productId, String productNo, String name, Long price,Long quantity) {
        this.productId = productId;
        this.productNo = productNo;
        this.name = name;
        this.price = price;
        this.quantity = quantity;
    }

    public static ProductListResponseDto of(Product product, Long quantity) {
        return ProductListResponseDto.builder()
                .productId(product.getId())
                .productNo(product.getProductNo())
                .name(product.getName())
                .price(product.getPrice())
                .quantity(quantity)
                .build();
    }

    public static ProductListResponseDto of(OrderDetail orderDetail) {
        return ProductListResponseDto.builder()
                .productId(orderDetail.getProduct().getId())
                .productNo(orderDetail.getProduct().getProductNo())
                .name(orderDetail.getProduct().getName())
                .price(orderDetail.getProduct().getPrice())
                .quantity(orderDetail.getQuantity())
                .build();
    }
}

 

현재 Product 엔티티의 Id는 @GeneratedValue(strategy = GenerationType.IDENTITY) 로 이루어져 있습니다.

추가적으로 @ActiveProfiles("test")에 해당하는 yml의 일부는 아래와 같습니다.

datasource:
  url: jdbc:h2:mem:~/Marketbridge
  driver-class-name: org.h2.Driver
  username: sa
  password:

jpa:
  hibernate:
    ddl-auto: none
  show-sql: true
  properties:
    hibernate:
      format_sql: true
      default_batch_fetch_size: 100
  defer-datasource-initialization: true

h2:
  console:
    enabled: true

이런 경우는 처음이라 어디가 잘못됐는지 찾지 못하겠네요 ㅠㅠ

답변 1

1

안녕하세요. 유선목님, 공식 서포터즈 y2gcoder입니다.

@GeneratedValue(strategy = GenerationType.IDENTITY)

를 통해 만드는 auto inrement 값은 트랜잭션 롤백의 영향을 받지 않습니다! 아래의 두 링크를 참고해주십쇼!

https://stackoverflow.com/questions/282451/sql-identity-autonumber-is-incremented-even-with-a-transaction-rollback

https://ymkmoon.github.io/Java-29-Jpa-Primary-Key/

 

감사합니다.

모깅님의 프로필 이미지
모깅
질문자

감사합니다!

모깅님의 프로필 이미지
모깅

작성한 질문수

질문하기