멋사 Backend Plus 31일차 🦁

μ‹ μž¬μ›Β·2023λ…„ 12μ›” 7일

μ˜€λŠ˜λ„ μ˜€μ „ μ˜€ν›„ νŒ€ ν”„λ‘œμ νŠΈλ₯Ό μ§„ν–‰ν•˜μ˜€κ³ , μž₯λ°”κ΅¬λ‹ˆ 등둝과 μž₯λ°”κ΅¬λ‹ˆ μ‘°νšŒμ— λŒ€ν•œ μ½”λ“œλ₯Ό λ¦¬νŒ©ν† λ§ ν•˜λŠ” ν•˜λ£¨ μ˜€λ‹€.

μ˜€μ „

  • μƒν’ˆμ„ μž₯λ°”κ΅¬λ‹ˆμ— λ‹΄κ³ , μƒν’ˆμ΄ λ‹΄κΈ΄ μž₯λ°”κ΅¬λ‹ˆλ₯Ό 쑰회 ν• μˆ˜ μžˆλŠ” κΈ°λŠ₯을 κ΅¬ν˜„ ν•˜μ˜€μŠ΅λ‹ˆλ‹€.
  • μƒν’ˆμ΄ λ‹΄κΈ΄ μž₯λ°”κ΅¬λ‹ˆ κΈ°λŠ₯은 mokito ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό μž‘μ„±ν•˜μ˜€κ³ , 정리 해보렀 ν•©λ‹ˆλ‹€.
@ExtendWith(MockitoExtension.class)
@Transactional
class CartServiceImplTest {

    @Mock
    private ItemCartRepository itemCartRepository;
    
    @InjectMocks
    private ItemCartServiceImpl itemCartService;

    @DisplayName("μœ μ €μ˜ μž₯λ°”κ΅¬λ‹ˆ 쑰회 확인")
    @Test
    public void read_Member_Cart_ByUser() {
        String findMemberName = "shin";
        List<ItemCart> mockItemCartList = new ArrayList<>();

        // Mockito.mock(μ‚¬μš©ν•  클래슀.class) -> 객체 생성, μ˜μ‘΄μ„± μ£Όμž…
        ItemCart mockItemCart = Mockito.mock(ItemCart.class);
        Cart mockCart = Mockito.mock(Cart.class);
        Member mockMember = Mockito.mock(Member.class);
        Product mockProduct = Mockito.mock(Product.class);

        // .thenReturn() -> λ°˜ν™˜ν•˜λŠ” 값을 μ§€μ •
        when(mockItemCart.getProduct()).thenReturn(mockProduct);
        when(mockItemCart.getCart()).thenReturn(mockCart);

        when(mockCart.getMember()).thenReturn(mockMember);
        when(mockMember.getUsername()).thenReturn(findMemberName);

        when(mockProduct.getProductName()).thenReturn("κ°•μ•„μ§€ 간식");
        when(mockProduct.getPrice()).thenReturn("25_000");
        when(mockItemCart.getStackCount()).thenReturn(3);

        // λͺ¨μ˜ 객체λ₯Ό λ¦¬μŠ€νŠΈμ— μΆ”κ°€
        mockItemCartList.add(mockItemCart);

        // itemCartRepository.findAll() 호좜 μ‹œ λͺ¨μ˜ 객체 리슀트 λ°˜ν™˜ν•˜λ„λ‘ μ„€μ •
        when(itemCartRepository.findAll()).thenReturn(mockItemCartList);

        List<ViewCartResponse> result = 
        	itemCartService.readMemberCartByUser(findMemberName);

        assertThat(1).isEqualTo(result.size());
        ViewCartResponse viewCartResponse = result.get(0);
        assertThat("κ°•μ•„μ§€ 간식")
        	.isEqualTo(viewCartResponse.getProductName());
        assertThat("25_000").isEqualTo(viewCartResponse.getPrice());
        Assertions.assertThat(3).isEqualTo(viewCartResponse.getCount());
    }
}

μ—°κ΄€κ΄€κ³„λ‘œ μ–½ν˜€ μžˆμ–΄ 쑰금 λ³΅μž‘ν•΄ λ³΄μ΄λŠ” μ½”λ“œ μ΄μ§€λ§Œ, mokito λ©”μ†Œλ“œλ₯Ό μ€‘μ‹¬μœΌλ‘œ μž‘μ„± ν•˜κ² μŠ΅λ‹ˆλ‹€.

Mockito.mock(μ‚¬μš©ν•  클래슀.class) : μ‚¬μš©ν•  클래슀 객체λ₯Ό 직접 μƒμ„±ν•˜μ§€ μ•Šκ³ , κ°€μ§œ (Mock) 객체λ₯Ό μ£Όμž…
when().thenReturn() : when μ•ˆ 의 λ©”μ†Œλ“œκ°€ 호좜 λ λ•Œ thenReturn μ•ˆ 의 객체λ₯Ό λ°˜ν™˜ν•˜λ„λ‘ μ§€μ •

μ±— GPT와 μ§ˆμ˜μ‘λ‹΅μ„ ν•˜λ©°, Mock ν…ŒμŠ€νŠΈλ₯Ό μž‘μ„± ν•˜μ˜€λŠ”λ°, Mock ν…ŒμŠ€νŠΈλ₯Ό μ™œ ν•΄μ•Όλ˜λŠ”μ§€, μ–΄λ– ν•œ κ²½μš°μ— μ‚¬μš©ν•˜λ©΄ 쒋은지도 μ•Œλ©΄ 쒋을 것 κ°™λ‹€.
(Mock ν…ŒμŠ€νŠΈ μ½”λ“œκ°€ 아직은 손에 μ•ˆ μ΅λŠ” 것 κ°™λ‹€.)

μ˜€ν›„

  • κΈ°λ³Έ μ‹œλ‚˜λ¦¬μ˜€λŠ”, μž₯λ°”κ΅¬λ‹ˆμ— μƒν’ˆμ„ λ‹΄κ³ , λ˜‘κ°™μ€ μƒν’ˆμ„ λ‹΄λŠ” 경우 객체λ₯Ό μƒˆλ‘œ μƒμ„±ν•˜μ§€ μ•Šκ³ , 기쑴에 μž₯λ°”κ΅¬λ‹ˆμ— λ‹΄κΈ΄ μƒν’ˆμ˜ 갯수만 증가 μ‹œν‚€λŠ” 것이 λͺ©ν‘œ μ˜€λ‹€.

  • μž₯λ°”κ΅¬λ‹ˆμ— μƒν’ˆμ„ λ‹΄λŠ” κΈ°λŠ₯

➑ findItemCart κ°€ null μ΄λΌλŠ” 것은, μž₯λ°”κ΅¬λ‹ˆμ— λ“±λ‘λœ μƒν’ˆμ΄ μ—†λ‹€. 즉 μž₯λ°”κ΅¬λ‹ˆκ°€ λΉ„μ–΄ μžˆλ‹€.

λ¬Όλ‘  μ•„λž˜μ™€ 같이 if 문을 2번 μ‚¬μš©ν•˜μ—¬ μ½”λ“œλ₯Ό μž‘μ„± 해도 λ˜μ§€λ§Œ, μ €λŠ” λ¦¬νŒ©ν† λ§ 뢀뢄이라고 μƒκ°ν•˜κ²Œ λ˜μ—ˆμŠ΅λ‹ˆλ‹€.
(else μ˜ˆμ•½μ–΄λ„ μ‚¬μš©μ„ μ§€μ–‘ ν–ˆλ‹€)

public void addProductByCart(Cart cart, Long productId, 
				ProductCountRequest productCountRequest) {
                
        ItemCart findItemCart = itemCartRepository
        	.findByCartIdAndProductId(cart.getId(), productId);

        if (findItemCart == null) {
            addToCartForNewProduct(cart, productId, productCountRequest);
        }
        
        if(findItemCart != null){
            addToCartForExistingProduct(findItemCart, cart,
            	productCountRequest);
        }
    }

μ½”λ“œλ₯Ό 고쳐가며 μ—¬λŸ¬ μ‹œν–‰ μ°©μ˜€κ°€ μžˆμ—ˆμ§€λ§Œ, μ•„λž˜μ˜ μ½”λ“œκ°€ κ°€μž₯ κΉ”λ”ν•˜κ³  κ°„κ²° ν•˜λ‹€κ³  μƒκ°ν•˜μ—¬ μž‘μ„±ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

if문의 쑰건이라면 return을 ν•  것이고, null 이 μ•„λ‹ˆλΌλ©΄ ifλ¬Έ λ°”κΉ₯의 둜직이 μ‹€ν–‰ 될 것 이닀.

 if (findItemCart == null) {
            addToCartForNewProduct(cart, productId, productCountRequest);
            return;
        }
        addToCartForExistingProduct(findItemCart, cart,
            	productCountRequest);

  • μƒˆλ‘œμš΄ μƒν’ˆμ„ μž₯λ°”κ΅¬λ‹ˆμ— λ‹΄λŠ” 경우

➑ μƒˆλ‘œμš΄ μƒν’ˆμ„ μž₯λ°”κ΅¬λ‹ˆμ— λ‹΄μ•„μ•Ό ν•¨μœΌλ‘œ, save() λ©”μ†Œλ“œλ₯Ό λ‘œμ§μ— μΆ”κ°€ μ‹œμΌœμ•Ό ν•˜λ©°, μž₯λ°”κ΅¬λ‹ˆμ™€ μ—°κ΄€λœ 객체λ₯Ό μ €μž₯ ν•΄μ€˜μ•Ό ν•©λ‹ˆλ‹€.
(EX : μž₯λ°”κ΅¬λ‹ˆμ™€ μƒν’ˆμ˜ 연관관계 λ“±)

private void addToCartForNewProduct(Cart cart, Long productId, 
			ProductCountRequest productCountRequest) {
            
        Product product = productService.getProduct(productId);
        cart.addCount(productCountRequest.getCount());
        ItemCart newItemCart = ItemCart
        	.createItemCart(cart, product, productCountRequest.getCount());
        newItemCart.removeStock(product, productCountRequest.getCount());
        itemCartRepository.save(newItemCart);
    }
  • 기쑴에 μž₯λ°”κ΅¬λ‹ˆμ— 담겨져 μžˆλŠ” μƒν’ˆμ„ λ‹΄λŠ” 경우

➑ κ°„λ‹¨νžˆ μ„€λͺ…ν•˜μ—¬, μž₯λ°”κ΅¬λ‹ˆμ— 이미 λ˜‘κ°™μ€ μƒν’ˆμ΄ 담겨져 μžˆμœΌλ‹ˆ save() λ©”μ†Œλ“œλ‘œ μ €μž₯을 ν•˜μ§€ μ•Šμ•„λ„ λœλ‹€λŠ” 점 μž…λ‹ˆλ‹€.

μž₯λ°”κ΅¬λ‹ˆμ— 담겨져 μžˆλŠ” μƒν’ˆμ„ find ν•˜μ—¬ 찾은 μƒν’ˆμ˜ 갯수만 add ν•˜λ©΄ λœλ‹€λŠ” 것 μž…λ‹ˆλ‹€.


private void addToCartForExistingProduct(ItemCart findItemCart, Cart cart, 
    		ProductCountRequest productCountRequest) {
            
        Product product = findItemCart.getProduct();
        findItemCart.removeStock(product, productCountRequest.getCount());
        cart.addCount(productCountRequest.getCount());
        findItemCart.addCount(productCountRequest.getCount());
    }

마무리

μ½”λ“œλ§Œ 주ꡬ μž₯μ°½ μž‘μ„±ν•˜λ©΄μ„œ 정리 ν•œ 것 κ°™μ•„, λ¨Όκ°€ λ³΅μž‘ν•΄ 보인닀. 내일은 ν‚€μ›Œλ“œμ— λŒ€ν•΄μ„œ 정리λ₯Ό ν•΄μ•Όκ² λ‹€.

0개의 λŒ“κΈ€