// given
// when
OrderResponse orderResponse = orderService.createOrder(request, registeredDateTime);
// then
assertThat(orderResponse.getId()).isNotNull();
assertThat(orderResponse)
.extracting("registeredDateTime", "totalPrice")
.contains(registeredDateTime, 4000);
// given
// when
OrderResponse orderResponse = orderService.createOrder(request, registeredDateTime);
// then
assertThat(orderResponse.getProducts()).hasSize(2)
.extracting("productNumber","price")
.containsExactlyInAnyOrder(
Tuple.tuple("001",1000),
Tuple.tuple("001",1000)
);
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OrderResponse {
Long orderId;
List<OrderDetailResponse> orderDetailResponses;
}
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OrderDetailResponse {
private Long orderDetailId;
private Long price;
private Long stock;
}
// given // when
List<OrderResponse> contents;
// then
Assertions.assertThat(contents)
.flatExtracting(orderResponse -> orderResponse.getOrderDetailResponses())
.extracting("price","stock")
.containsExactlyInAnyOrder(
Tuple.tuple(10000,100),
Tuple.tuple(20000,200)
);
// when
List<Store> result = storeService.getStoresForAdmin(page, sort, sidoCode, gugunCode).getContent();
// then
assertThat(result).hasSize(3);
IntStream.range(1, result.size()).forEach(i -> {
Store prev = result.get(i-1);
Store next = result.get(i);
assertThat(prev.getCreatedAt().isAfter(next.getCreatedAt())).isTrue();
});
// given
// when // then
assertThatThrownBy(() -> orderService.createOrder(request, registeredDateTime))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("재고가 부족한 상품이 있습니다.");
private static Stream<Arguments> prodvideProductTypesForCheckingStockType(){
return Stream.of(
Arguments.of(ProductType.HANDMADE, false),
Arguments.of(ProductType.BOTTLE, true),
Arguments.of(ProductType.BAKERY, true)
);
}
@DisplayName("상품 타입이 재고 관련 타입인지를 체크한다.")
@MethodSource("prodvideProductTypesForCheckingStockType")
@ParameterizedTest
void containsStockType4(ProductType productType, boolean expected){
// when
boolean result = ProductType.containsStockType(productType);
// then
assertThat(result).isEqualTo(expected);
}
@DisplayName("주문이 완료됐지만 결제가 성공하지 않았으면 결제 상태를 보여준다")
@ParameterizedTest
@EnumSource(value = PaymentStatus.class, names = {"READY","CANCELED","FAILED"}, mode = EnumSource.Mode.INCLUDE)
void enumTest(PaymentStatus paymentStatus) {
// given
OrderDetail orderDetail = createOrderDetail(paymentStatus);
// when
String result = orderDetail.getFinalStatusAsString();
// then
Assertions.assertThat(result).isEqualTo(paymentStatus.getMessage());
}
ParameterizedTest말고 일반 테스트에서 eunm값을 비교하고 싶다면 .isEqualTo()
가 아니라 isEqualByComparingTo()
를 쓰면 된다
@DisplayName("상품 타입이 재고 관련 타입인지를 체크한다.")
@CsvSource({"HANDMADE,false","BOTTLE,true","BAKERY,true"})
@ParameterizedTest
void containsStockType3(ProductType productType, boolean expected){
// when
boolean result = ProductType.containsStockType(productType);
// then
assertThat(result).isEqualTo(expected);
}
기본 형태
@DisplayName("")
@TestFactory
Collection<DynamicTest> dynamicTest(){
return List.of(
DynamicTest.dynamicTest("Description",() -> {
}),
DynamicTest.dynamicTest("Description",() -> {
})
);
}
@DisplayName("재고 차감 시나리오")
@TestFactory
Collection<DynamicTest> stockDeductionDynamicTest(){
// given
Stock stock = Stock.create("001",1);
return List.of(
DynamicTest.dynamicTest("재고를 주어진 개수만큼 차가할 수 있다.",() -> {
// given
int quantity = 1;
// when
stock.deductQuantity(quantity);
// then
assertThat(stock.getQuantity()).isZero();
}),
// 이전 시나리오에서 quantity가 1 차감된 상태가 여전히 유지되고 있음
DynamicTest.dynamicTest("재고보다 많은 수의 수량으로 차감 시도하는 경우 예외가 발생한다",() -> {
// given
int quantity = 1;
// when // then
assertThatThrownBy(() -> stock.deductQuantity(quantity))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("차감할 재고 수량이 없습니다.");
})
);
}
@ExtendWith(MockitoExtension.class)
@SpringBootTest
@Transactional
class OrchestratorServiceTest {
@MockBean
private BeanA beanA;
@Autowired BeanB beanB;
@InjeckMocks
private BeanC beanC; // beanA만 주입받으면 됨
// 별도로 어노테이션 안붙음
private BeanD beanD; // beanA와 beanB를 주입받아야 함
@BeforeEach
public void beforeEach(){
beanD = new beanD(beanA,beanB);
}
BDDMockito.given(paymentFeignClient.kakaopayReady(BDDMockito.any()))
.willReturn(ResponseEntity.ok().body("URL"));
BDDMockito.given(inventoryFeignClient.deductNormalQuantity(BDDMockito.any()))
.willThrow(new RuntimeException());
BDDMockito.doNothing().when(kafkaProducer)
.send(BDDMockito.any(),BDDMockito.any());
BDDMockito.verify(cartFeignClient).removeItems(BDDMockito.any());
@WebMvcTest(controllers = {
OrderController.class,
ProductController.class
})
public abstract class ControllerTestSupport {
@Autowired
protected MockMvc mockMvc;
@Autowired
protected ObjectMapper objectMapper;
@MockBean
protected OrderService orderService;
@MockBean
protected ProductService productService;
}
class ProductControllerTest extends ControllerTestSupport {
@DisplayName("신규 상품을 등록할 때 상품 타입은 필수값이다.")
@Test
void createProductWithoutType() throws Exception{
// given
// when // then
mockMvc.perform(MockMvcRequestBuilders.post("/api/v1/products/new")
.content(objectMapper.writeValueAsString(request)) // String 혹은 byte형태로 넣어주면 됨, 객체를 넣으려면 직렬화 과정이 필요
.contentType(MediaType.APPLICATION_JSON)
)
.andDo(MockMvcResultHandlers.print())
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.code").value("400"))
.andExpect(jsonPath("$.status").value("BAD_REQUEST"))
.andExpect(jsonPath("$.message").value("상품 타입은 필수입니다."))
.andExpect(jsonPath("$.data").isEmpty());
}
}
$
가 된다. $.변수
가 객체인 경우 $.변수.변수
도 가능하다.