요구사항
- 키오스크 주문을 위한 상품 후보 리스트 조회하기
- 상품의 판매 상태: 판매중, 판매보류, 판매중시
- 판매중, 판매보류인 상태의 상품을 화면에 보여준다.
- id, 상품 번호, 상품 타입, 판매 상태, 상품 이름, 가격
엔티티 설계
@Entity
@NoArgsConstructor(access = PROTECTED)
@Getter
public class Product {
@Id @GeneratedValue(strategy = IDENTITY)
private Long id;
private String productNumber;
@Enumerated(STRING)
private ProductType type;
@Enumerated(STRING)
private ProductSellingStatus sellingStatus;
private String name;
private int price;
@Builder
public Product(String productNumber, ProductType type, ProductSellingStatus sellingStatus,
String name, int price) {
this.productNumber = productNumber;
this.type = type;
this.sellingStatus = sellingStatus;
this.name = name;
this.price = price;
}
}
BaseEntity
@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseEntity {
@CreatedDate
private LocalDateTime createdDateTime;
@LastModifiedDate
private LocalDateTime modifiedDateTime;
}
Enum
@Getter
@RequiredArgsConstructor
public enum ProductType {
HANDMADE("제조 음료"),
BOTTLE("병 음료"),
BAKERY("베이커리");
private final String text;
}
@Getter
@RequiredArgsConstructor
public enum ProductSellingStatus {
SELLING("판매중"),
HOLD("판매보류"),
STOP_SELLING("판매중지");
private final String text;
public static List<ProductSellingStatus> forDisplay() {
return List.of(SELLING, HOLD);
}
}
Repository 작성
public interface ProductRepository extends JpaRepository<Product, Long> {
/**
* select *
* from product
* where selling_type in ("SELLING", "HOLD");
*/
List<Product> findAllBySellingStatusIn(List<ProductSellingStatus> sellingStatuses);
}
Service 작성
@RequiredArgsConstructor
@Service
public class ProductService {
private final ProductRepository productRepository;
public List<ProductResponse> getSellingProducts() {
List<Product> products = productRepository.findAllBySellingStatusIn(
ProductSellingStatus.forDisplay());
return products.stream()
.map(ProductResponse::of)
.collect(toList());
}
}
Controller 작성
@RequiredArgsConstructor
@RestController
public class ProductController {
private final ProductService productService;
@GetMapping("/api/v1/products/selling")
public List<ProductResponse> getSellingProducts() {
return productService.getSellingProducts();
}
}
Dto
@Getter
public class ProductResponse {
private Long id;
private String productNumber;
private ProductType type;
private ProductSellingStatus sellingStatus;
private String name;
private int price;
@Builder
public ProductResponse(Long id, String productNumber, ProductType type,
ProductSellingStatus sellingStatus, String name, int price) {
this.id = id;
this.productNumber = productNumber;
this.type = type;
this.sellingStatus = sellingStatus;
this.name = name;
this.price = price;
}
public static ProductResponse of(Product product) {
return ProductResponse.builder()
.id(product.getId())
.productNumber(product.getProductNumber())
.type(product.getType())
.sellingStatus(product.getSellingStatus())
.name(product.getName())
.price(product.getPrice())
.build();
}
}
Repository 테스트
- 간단한 쿼리메서드인경우 딱히 확인이 필요없다. 생각이 들지만 실무는 간단하지 않다.
@ActiveProfiles("test")
//@SpringBootTest
@DataJpaTest
class ProductRepositoryTest {
@Autowired
private ProductRepository productRepository;
@DisplayName("원하는 판매상태를 가진 상품들을 조회한다.")
@Test
void findAllBySellingStatusIn() {
// given
Product product1 = Product.builder()
.productNumber("001")
.type(BAKERY)
.sellingStatus(SELLING)
.name("아메리카노")
.price(4000)
.build();
Product product2 = Product.builder()
.productNumber("002")
.type(BAKERY)
.sellingStatus(HOLD)
.name("카페라떼")
.price(4500)
.build();
Product product3 = Product.builder()
.productNumber("003")
.type(HANDMADE)
.sellingStatus(STOP_SELLING)
.name("팥빙수")
.price(7000)
.build();
productRepository.saveAll(List.of(product1, product2, product3));
// when
List<Product> products = productRepository.findAllBySellingStatusIn(
List.of(SELLING, HOLD));
// then
assertThat(products).hasSize(2)
.extracting("productNumber", "name", "sellingStatus")
.containsExactlyInAnyOrder(
tuple("001", "아메리카노", SELLING),
tuple("002", "카페라떼", HOLD)
);
}
}
- @DataJpaTest와 @SpringBootTest는 비슷하지만
- @DataJpaTest는 Jpa관련 빈들만 불러온다.
- @SpringBootTest는 Spring Server를 띄어서 확인해 볼 수 있는 어노테이션이다.
- extracting: 검증하고자 하는 필드만 추출할 수 있음
- containsExactlyInAnyOrder: 순서 상관없이 필드의 값을 확인해주는 메서드 체이닝 검증 기법
- ActiveProfiles 설정관련
spring:
config:
activate:
on-profile: test
jpa:
hibernate:
ddl-auto: create
show-sql: true
properties:
hibernate:
format_sql: true
sql:
init:
mode: never
'Spring관련 기술 > 테스트코드' 카테고리의 다른 글
Business Layer 테스트 (2) (0) | 2023.12.17 |
---|---|
Business Layer 테스트 (1) (0) | 2023.12.14 |
Spring & JPA 기반 테스트 (0) | 2023.12.13 |
BDD, Behavior Driven Development (0) | 2023.12.12 |
@DisplayName (0) | 2023.12.12 |