테스트코드/작성방법

5. Business Layer Test

feel2 2024. 3. 26. 08:04
반응형

Business Layer, 비즈니스 계층은 서비스의 핵심 로직이 집중 되어 있는 계층이다. 서비스 로직은 보통 데이터를 다루므로 Business Layer은 단독 계층 테스트가 아닌, Persistence Layer 와 함께 통합적으로 테스트를 진행한다.
서비스 테스트를 진행하며, 테스트에 용이하게 로직을 개선하면서 전체적인 로직도 개선되는 선순환을 만들 수 있도록 해보자. ( 관심 있다면 TDD 개념도 살펴보면 좋을 것 같다.)

5.1. 기본적인 Business Layer Test

 

비즈니스 계층 테스트에서 테스트관련 새로운 내용은 상대적으로 없으나, 샘플로 작성한 서비스 로직, 엔티티 관계에 대해 먼저 살펴보고 서비스 테스트 내용을 보는 걸 추천한다.

 

5.1.1. Entity 준비

 

비즈니스 로직을 작성하기 앞서 엔티티 관계와 구현하고자 하는 서비스를 소개를 한다.

상품 - 상품주문 - 주문

 

상품을 생성하면 엔티티 관계에 의해 주문상품 데이터 그리고 주문 데이터가 생성된다.
상품과 주문의 서비스 내용:
상품 서비스: 신규 상품 추가(생성)한다. 상품이 추가 생성될 때 상품 번호는 최근 상품의 상품 번호에서 1 이 증가한 값이다. 상품이 하나도 없는 경이 신규 상품이 추가되는 경우면 상품 번호는 ‘001’ 이 할당된다.

 

package msa.tc.order.domain;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import msa.tc.orderproduct.domain.OrderProductEntity;


import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "orders") // db 예약어이여서 달리 명시함
@Entity
public class OrderEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Enumerated(EnumType.STRING)
    private OrderStatus orderStatus;

    private int totalPrice;

    private LocalDateTime registeredDateTime;

    // 연관관계 주인 (필드명으로 설정), Order 가 cud 될 때, 같이 반영 되도록 생명주기도 all 로 설정
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
    private List<OrderProductEntity> orderProducts = new ArrayList<>();
}

 

package simple.testcode.order.domain;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum OrderStatus {

    INIT("주문생성"),
    CANCELED("주문취소"),
    PAYMENT_COMPLETED("결제완료"),
    PAYMENT_FAILED("결제실패"),
    RECEIVED("주문접수"),
    COMPLETED("처리완료");

    private final String text;
}

 

package simple.testcode.orderproduct.domain;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import simple.testcode.order.domain.OrderEntity;
import simple.testcode.product.domain.ProductEntity;

import javax.persistence.*;

/**
 * 중간 테이블
 * Order - Product
 */
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Table(name = "orderProduct")
public class OrderProductEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // ManyToOne 경우에는 필요한 시점에 데이터를 조회하기 위해, 보통 lazy fetch
    @ManyToOne(fetch = FetchType.LAZY)
    private OrderEntity order;

    @ManyToOne(fetch = FetchType.LAZY)
    private ProductEntity product;

    public OrderProductEntity(OrderEntity order, ProductEntity product) {
        this.order = order;
        this.product = product;
    }
}

 

5.1.2. Business Layer Test

 

비즈니스 계층 테스트에서는 스프링 컨테이너가 제공하는 서비스 빈부터 데이터 접근이 가능한 Bean 등 복수개의 계층에서 다양한 Bean들이 필요하다. @SpringBootTest 애노테이션을 사용하자.

 

상품 요청 관련 응답 객체 준비, 상품 관련 서비스, 상품서비스 테스트 추가

*request, *response, *serviceVo: service layer 전용, 책임 분리, 의존성 분리, 확장 용이성을 위함 (e.g. ProductRequest, ProductResponse, ProductServiceVo)

package msa.tc.product.dto;

import lombok.Builder;
import lombok.Getter;
import msa.tc.product.domain.ProductEntity;
import msa.tc.product.domain.ProductSellingStatus;

/**
 * 상품 응답 전용 vo
 */
@Getter
public class ProductResponse {
    private Long id;

    private String productNumber;

    private ProductSellingStatus sellingStatus;

    private String name;

    private int price;

    @Builder
    private ProductResponse(Long id, String productNumber, ProductSellingStatus sellingStatus, String name, int price) {
        this.id = id;
        this.productNumber = productNumber;
        this.sellingStatus = sellingStatus;
        this.name = name;
        this.price = price;
    }

    // entity -> vo
    public static ProductResponse of(ProductEntity product) {
        return ProductResponse.builder()
                .id(product.getId())
                .productNumber(product.getProductNumber())
                .sellingStatus(product.getSellingStatus())
                .name(product.getName())
                .price(product.getPrice())
                .build();
    }
}

 

 

package msa.tc.product.dto;

import lombok.Builder;
import msa.tc.product.domain.ProductEntity;
import msa.tc.product.domain.ProductSellingStatus;

/**
 * 상품 서비스 전용 vo
 * service layer 전용, 책임 분리, 의존성 분리, 확장 용이성
 */
public class ProductServiceVo {

    private ProductSellingStatus sellingStatus;
    private String name;
    private int price;

    @Builder
    private ProductServiceVo(ProductSellingStatus sellingStatus, String name, int price) {
        this.sellingStatus = sellingStatus;
        this.name = name;
        this.price = price;
    }

    public ProductEntity toEntity(String nextProductNumber) {
        return ProductEntity.builder()
                .productNumber(nextProductNumber)
                .sellingStatus(sellingStatus)
                .name(name)
                .price(price)
                .build();
    }
}

 

package msa.tc.product.service;


import lombok.RequiredArgsConstructor;
import msa.tc.product.dao.ProductRepository;
import msa.tc.product.domain.ProductEntity;
import msa.tc.product.dto.ProductResponse;
import msa.tc.product.dto.ProductServiceVo;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Transactional(readOnly = true)
@RequiredArgsConstructor
@Service
public class ProductService {

    private final ProductRepository productRepository;

    @Transactional
    public ProductResponse createProduct(ProductServiceVo productCreateServiceRequestVo) {
        String nextProductNumber = this.createNextProductNumber();

        ProductEntity product = productCreateServiceRequestVo.toEntity(nextProductNumber);
        ProductEntity savedProduct = productRepository.save(product);

        return ProductResponse.of(savedProduct);
    }

    /**
     * 다음 상품 번호 generator
     */
    private String createNextProductNumber() {
        String latestProductNumber = productRepository. findLatestProductNumber();
        if (latestProductNumber == null) {
            return "001";
        }

        int latestProductNumberInt = Integer.valueOf(latestProductNumber);
        int nextProductNumberInt = latestProductNumberInt + 1;

        // 9 -> 009, 10 -> 010
        return String.format("%03d", nextProductNumberInt);
    }
}

 

상품 서비스 테스트 코드이다. 신규 상품 추가(생성) 서비스 에 대해 2가지 테스트를 진행하였으며, 예외 케이스(경계값) 도 포함되어 있다. 테스트명은 문장으로 작성하였다.

 

package msa.tc.product.service;

import msa.tc.product.dao.ProductRepository;
import msa.tc.product.domain.ProductEntity;
import msa.tc.product.domain.ProductSellingStatus;
import msa.tc.product.dto.ProductResponse;
import msa.tc.product.dto.ProductServiceVo;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import static org.junit.jupiter.api.Assertions.*;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;

@SpringBootTest
class ProductServiceTest {

    @Autowired
    private ProductService productService;

    @Autowired private ProductRepository productRepository;

    @DisplayName("신규 상품을 추가한다. 상품번호는 가장 최근 상품의 상품번호에서 1 증가한 값이다.")
    @Test
    void createProduct() {
        // given
        ProductEntity product1 = createProduct("001", ProductSellingStatus.SELLING, "아메리카노", 4000);
        productRepository.save(product1);

        ProductServiceVo productServiceVo = ProductServiceVo.builder()
                .sellingStatus(ProductSellingStatus.SELLING)
                .name("카푸치노")
                .price(5700)
                .build();


        // when
        ProductResponse productResponse = productService.createProduct(productServiceVo);


        // then
        assertThat(productResponse)
                .extracting("productNumber", "sellingStatus", "name", "price")
                .contains("002", ProductSellingStatus.SELLING, "카푸치노", 5700);

        // 상품 저장 확인
        List<ProductEntity> products = productRepository.findAll();
        assertThat(products).hasSize(2)
                .extracting("productNumber", "sellingStatus", "name", "price")
                .containsExactlyInAnyOrder(
                        tuple("001", ProductSellingStatus.SELLING, "아메리카노", 4000),
                        tuple("002", ProductSellingStatus.SELLING, "카푸치노", 5700)
                );
    }

    @DisplayName("상품이 하나도 없는 경우, 신규 상품을 추가하면, 상품 번호는 001 이다.")
    @Test
    void createProductWhenProductsIsEmpty() {
        clearData();
        // given
        // 기존의 product 데이터 있다면 지우기 (clearData() 에서 구현함)
        ProductServiceVo productServiceVo = ProductServiceVo.builder()
                .sellingStatus(ProductSellingStatus.SELLING)
                .name("카푸치노")
                .price(5700)
                .build();


        // when
        ProductResponse productResponse = productService.createProduct(productServiceVo);


        // then
        assertThat(productResponse)
                .extracting("productNumber", "sellingStatus", "name", "price")
                .contains("001", ProductSellingStatus.SELLING, "카푸치노", 5700);

        // 상품 저장 확인
        List<ProductEntity> products = productRepository.findAll();
        assertThat(products).hasSize(1)
                .extracting("productNumber", "sellingStatus", "name", "price")
                .contains(
                        tuple("001", ProductSellingStatus.SELLING, "카푸치노", 5700)
                );
    }

    private void clearData() {
        productRepository.deleteAllInBatch();
    }

    private ProductEntity createProduct(String productNumber, ProductSellingStatus sellingStatus, String name, int price) {
        return ProductEntity.builder()
                .productNumber(productNumber)
                .sellingStatus(sellingStatus)
                .name(name)
                .price(price)
                .build();
    }
}

 

상품이 하나도 없는 경우, 신규 상품을 추가하면, 상품 번호는 001 이다. 테스트를 진행하기 위해, 데이터를 클렌징 하였다.

 

private void clearData() {
    productRepository.deleteAllInBatch();
}

 

5.2. Business Layer Test 예제

 

Business Layer 테스트 작성 - 2 주문 관련 서비스, 서비스 테스트 추가

package msa.tc.order.domain;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import msa.tc.orderproduct.domain.OrderProductEntity;
import msa.tc.product.domain.ProductEntity;


import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "orders") // db 예약어이여서 달리 명시함
@Entity
public class OrderEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Enumerated(EnumType.STRING)
    private OrderStatus orderStatus;

    private int totalPrice;

    private LocalDateTime registeredDateTime;

    // 연관관계 주인 (필드명으로 설정), Order 가 cud 될 때, 같이 반영 되도록 생명주기도 all 로 설정
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
    private List<OrderProductEntity> orderProducts = new ArrayList<>();

    private int calculateTotalPrice(List<ProductEntity> products) {
        return products.stream()
                .mapToInt(ProductEntity::getPrice)
                .sum();
    }


    @Builder
    public OrderEntity(List<ProductEntity> products, OrderStatus orderStatus, LocalDateTime registeredDateTime) {
        this.orderStatus = orderStatus;
        this.totalPrice = calculateTotalPrice(products);
        this.registeredDateTime = registeredDateTime;
        this.orderProducts = products.stream()
                .map(product -> new OrderProductEntity(this, product))
                .collect(Collectors.toList());
    }

    public static OrderEntity create(List<ProductEntity> products, LocalDateTime registeredDateTime) {
        return OrderEntity.builder()
                .orderStatus(OrderStatus.INIT)
                .products(products)
                .registeredDateTime(registeredDateTime)
                .build();
    }
}

 

 

package msa.tc.order.dto;

import lombok.Builder;
import lombok.Getter;

import java.util.List;

@Getter
// 서비스 전용 vo
// service layer 전용, 책임 분리, 의존성 분리, 확장 용이성
public class OrderServiceVo {

    private List<String> productNumbers;

    @Builder
    private OrderServiceVo(List<String> productNumbers) {
        this.productNumbers = productNumbers;
    }
}

 

 

package msa.tc.order.dto;

import lombok.Builder;
import lombok.Getter;
import msa.tc.order.domain.OrderEntity;
import msa.tc.product.dto.ProductResponse;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Getter
public class OrderResponse {

    private Long id;

    private int totalPrice;
    private LocalDateTime registeredDateTime;

    // Order 클래스의 맴버 orderProducts 를 그대로 사용하는 것 보단 응답 로직 전용 객체 ProductResponse 로 바꿔서 선언
    private List<ProductResponse> products; // List<OrderProduct> orderProducts

    @Builder
    private OrderResponse(Long id, int totalPrice, LocalDateTime registeredDateTime, List<ProductResponse> products) {
        this.id = id;
        this.totalPrice = totalPrice;
        this.registeredDateTime = registeredDateTime;
        this.products = products;
    }

    public static OrderResponse of(OrderEntity order) {
        return OrderResponse.builder()
                .id(order.getId())
                .totalPrice(order.getTotalPrice())
                .registeredDateTime(order.getRegisteredDateTime())
                // OrderProduct <<>> ProductResponse mapping 부분
                .products(order.getOrderProducts().stream()
                        .map(orderProduct -> ProductResponse.of(orderProduct.getProduct()))
                        .collect(Collectors.toList())
                )
                .build();
    }
}

 

 

package msa.tc.order.service;


import lombok.RequiredArgsConstructor;
import msa.tc.order.dao.OrderRepository;
import msa.tc.order.domain.OrderEntity;
import msa.tc.order.dto.OrderResponse;
import msa.tc.order.dto.OrderServiceVo;
import msa.tc.product.dao.ProductRepository;
import msa.tc.product.domain.ProductEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Transactional(readOnly = true)
@RequiredArgsConstructor
@Service
public class OrderService {

    private final ProductRepository productRepository;
    private final OrderRepository orderRepository;

    @Transactional
    public OrderResponse createOrder(OrderServiceVo orderCreateServiceRequestVo, LocalDateTime registeredDateTime) {

        // Product
        List<String> productNumbers = orderCreateServiceRequestVo.getProductNumbers();
        List<ProductEntity> products = findProductsBy(productNumbers);

        // Order
        OrderEntity order = OrderEntity.create(products, registeredDateTime);
        OrderEntity savedOrder = orderRepository.save(order);

        return OrderResponse.of(savedOrder);
    }

    /**
     * 상품번호로 상품 조회, 중복되는 상품번호 목록으로 주문 가능
     */
    private List<ProductEntity> findProductsBy(List<String> productNumbers) {
        List<ProductEntity> products = productRepository.findAllByProductNumberIn(productNumbers);
        Map<String, ProductEntity> productMap = products.stream()
                .collect(Collectors.toMap(ProductEntity::getProductNumber, p -> p));

        return productNumbers.stream()
                .map(productMap::get)
                .collect(Collectors.toList());
    }
}

 

 

package msa.tc.order.service;

import msa.tc.order.dto.OrderRequest;
import msa.tc.order.dto.OrderResponse;
import msa.tc.order.dto.OrderServiceVo;
import msa.tc.product.dao.ProductRepository;
import msa.tc.product.domain.ProductEntity;
import msa.tc.product.domain.ProductSellingStatus;
import org.assertj.core.groups.Tuple;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.time.LocalDateTime;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;

@SpringBootTest
class OrderServiceTest {


    @Autowired
    private OrderService orderService;

    @Autowired
    private ProductRepository productRepository;

    @DisplayName("주문번호 리스트를 받아 주문을 생성한다.")
    @Test
    void createOrder() {

        // given
        LocalDateTime registeredDateTime = LocalDateTime.now();

        ProductEntity product1 = this.createProduct("001", 1000);
        ProductEntity product2 = this.createProduct("002", 2000);
        ProductEntity product3 = this.createProduct("003", 7000);

        productRepository.saveAll(List.of(product1, product2, product3));

        OrderServiceVo orderServiceVo = OrderServiceVo.builder()
                .productNumbers(List.of("001", "002"))
                .build();


        // when
        OrderResponse orderResponse = orderService.createOrder(orderServiceVo, registeredDateTime);


        // then
        assertThat(orderResponse.getId()).isNotNull();

        assertThat(orderResponse)
                .extracting("registeredDateTime", "totalPrice")
                .contains(registeredDateTime, 3000);

        assertThat(orderResponse.getProducts()).hasSize(2)
                .extracting("productNumber", "price")
                .containsExactlyInAnyOrder(
                        Tuple.tuple("001", 1000),
                        Tuple.tuple("002", 2000)
                );
    }

    private ProductEntity createProduct(String productNumber, int price) {
        return ProductEntity.builder()
                .productNumber(productNumber)
                .price(price)
                .sellingStatus(ProductSellingStatus.SELLING)
                .name("샘플 메뉴 이름")
                .build();
    }

}

 

 

2023-10-12 10:13:29.220 DEBUG 71864 --- [           main] org.hibernate.SQL                        :
    insert
    into
        product
        (id, name, price, product_number, selling_status)
    values
        (default, ?, ?, ?, ?)
2023-10-12 10:13:29.224 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [샘플 메뉴 이름]
2023-10-12 10:13:29.224 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [INTEGER] - [1000]
2023-10-12 10:13:29.224 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [VARCHAR] - [001]
2023-10-12 10:13:29.224 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [4] as [VARCHAR] - [SELLING]
2023-10-12 10:13:29.232 DEBUG 71864 --- [           main] org.hibernate.SQL                        :
    insert
    into
        product
        (id, name, price, product_number, selling_status)
    values
        (default, ?, ?, ?, ?)
2023-10-12 10:13:29.232 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [샘플 메뉴 이름]
2023-10-12 10:13:29.232 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [INTEGER] - [2000]
2023-10-12 10:13:29.232 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [VARCHAR] - [002]
2023-10-12 10:13:29.232 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [4] as [VARCHAR] - [SELLING]
2023-10-12 10:13:29.233 DEBUG 71864 --- [           main] org.hibernate.SQL                        :
    insert
    into
        product
        (id, name, price, product_number, selling_status)
    values
        (default, ?, ?, ?, ?)
2023-10-12 10:13:29.233 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [샘플 메뉴 이름]
2023-10-12 10:13:29.233 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [INTEGER] - [7000]
2023-10-12 10:13:29.233 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [VARCHAR] - [003]
2023-10-12 10:13:29.233 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [4] as [VARCHAR] - [SELLING]
2023-10-12 10:13:29.312 DEBUG 71864 --- [           main] org.hibernate.SQL                        :
    select
        productent0_.id as id1_2_,
        productent0_.name as name2_2_,
        productent0_.price as price3_2_,
        productent0_.product_number as product_4_2_,
        productent0_.selling_status as selling_5_2_
    from
        product productent0_
    where
        productent0_.product_number in (
            ? , ?
        )
2023-10-12 10:13:29.312 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [001]
2023-10-12 10:13:29.313 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [VARCHAR] - [002]
2023-10-12 10:13:29.313 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([id1_2_] : [BIGINT]) - [1]
2023-10-12 10:13:29.315 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([name2_2_] : [VARCHAR]) - [샘플 메뉴 이름]
2023-10-12 10:13:29.315 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([price3_2_] : [INTEGER]) - [1000]
2023-10-12 10:13:29.315 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([product_4_2_] : [VARCHAR]) - [001]
2023-10-12 10:13:29.315 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([selling_5_2_] : [VARCHAR]) - [SELLING]
2023-10-12 10:13:29.315 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([id1_2_] : [BIGINT]) - [2]
2023-10-12 10:13:29.315 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([name2_2_] : [VARCHAR]) - [샘플 메뉴 이름]
2023-10-12 10:13:29.315 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([price3_2_] : [INTEGER]) - [2000]
2023-10-12 10:13:29.315 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([product_4_2_] : [VARCHAR]) - [002]
2023-10-12 10:13:29.315 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicExtractor   : extracted value ([selling_5_2_] : [VARCHAR]) - [SELLING]
2023-10-12 10:13:29.323 DEBUG 71864 --- [           main] org.hibernate.SQL                        :
    insert
    into
        orders
        (id, created_date_time, modified_date_time, order_status, registered_date_time, total_price)
    values
        (default, ?, ?, ?, ?, ?)
2023-10-12 10:13:29.324 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [TIMESTAMP] - [null]
2023-10-12 10:13:29.324 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [TIMESTAMP] - [null]
2023-10-12 10:13:29.324 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [VARCHAR] - [INIT]
2023-10-12 10:13:29.324 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [4] as [TIMESTAMP] - [2023-10-12T10:13:29.199453]
2023-10-12 10:13:29.325 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [5] as [INTEGER] - [3000]
2023-10-12 10:13:29.326 DEBUG 71864 --- [           main] org.hibernate.SQL                        :
    insert
    into
        order_product
        (id, order_id, product_id)
    values
        (default, ?, ?)
2023-10-12 10:13:29.327 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BIGINT] - [1]
2023-10-12 10:13:29.327 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [BIGINT] - [1]
2023-10-12 10:13:29.328 DEBUG 71864 --- [           main] org.hibernate.SQL                        :
    insert
    into
        order_product
        (id, order_id, product_id)
    values
        (default, ?, ?)
2023-10-12 10:13:29.328 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [BIGINT] - [1]
2023-10-12 10:13:29.328 TRACE 71864 --- [           main] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [BIGINT] - [2]

 

반응형

'테스트코드 > 작성방법' 카테고리의 다른 글

7. End to End 테스트  (0) 2024.03.26
6. Presentation Layer Test  (1) 2024.03.26
4. 외부 시스템과의 연계 테스트  (1) 2024.03.26
3. Persistence Layer Test  (0) 2024.03.26
2. Layered Architecture  (0) 2024.03.26