-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: Stubbing mail send service test
- Loading branch information
Showing
11 changed files
with
337 additions
and
11 deletions.
There are no files selected for viewing
31 changes: 31 additions & 0 deletions
31
src/main/java/sample/cafekiosk/spring/api/service/mail/MailService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package sample.cafekiosk.spring.api.service.mail; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import sample.cafekiosk.spring.client.mail.MailSendClient; | ||
import sample.cafekiosk.spring.domain.history.mail.MailSendHistory; | ||
import sample.cafekiosk.spring.domain.history.mail.MailSendHistoryRepository; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class MailService { | ||
|
||
private final MailSendClient mailSendClient; | ||
private final MailSendHistoryRepository mailSendHistoryRepository; | ||
|
||
public boolean sendMail(String fromEmail, String toEmail, String subject, String content) { | ||
boolean result = mailSendClient.sendEmail(fromEmail, toEmail, subject, content); | ||
|
||
if (result) { | ||
mailSendHistoryRepository.save(MailSendHistory.builder() | ||
.fromMail(fromEmail) | ||
.toEmail(toEmail) | ||
.subject(subject) | ||
.content(content) | ||
.build()); | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
src/main/java/sample/cafekiosk/spring/api/service/order/OrderStatisticsService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package sample.cafekiosk.spring.api.service.order; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import sample.cafekiosk.spring.api.service.mail.MailService; | ||
import sample.cafekiosk.spring.domain.order.Order; | ||
import sample.cafekiosk.spring.domain.order.OrderRepository; | ||
import sample.cafekiosk.spring.domain.order.OrderStatus; | ||
|
||
import java.time.LocalDate; | ||
import java.util.List; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class OrderStatisticsService { | ||
|
||
private final MailService mailService; | ||
private final OrderRepository orderRepository; | ||
|
||
public boolean sendOrderStatisticsMail(LocalDate orderDate, String email) { | ||
// 해당 일자에 결제완료된 주문들을 가져와서 | ||
List<Order> orders = orderRepository.findOrdersBy( | ||
orderDate.atStartOfDay(), | ||
orderDate.plusDays(1).atStartOfDay(), | ||
OrderStatus.PAYMENT_COMPLETED | ||
); | ||
// 총 매출 합계를 계산하고 | ||
|
||
int totalAmount = orders.stream().mapToInt(Order::getTotalPrice).sum(); | ||
|
||
// 메일 전송 | ||
boolean result = mailService.sendMail("[email protected]", | ||
email, | ||
String.format("[매출통계] %s", orderDate), | ||
String.format("총 매출 합계는 %s원입니다.", totalAmount) | ||
); | ||
|
||
if (!result) { | ||
throw new IllegalArgumentException("매출 통계 메일 전송에 실패했습니다."); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
} |
13 changes: 13 additions & 0 deletions
13
src/main/java/sample/cafekiosk/spring/client/mail/MailSendClient.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package sample.cafekiosk.spring.client.mail; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Component | ||
@Slf4j | ||
public class MailSendClient { | ||
public boolean sendEmail(String fromEmail, String toEmail, String subject, String content) { | ||
log.info("메일 전송"); | ||
throw new IllegalArgumentException("메일 전송"); | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
src/main/java/sample/cafekiosk/spring/domain/history/mail/MailSendHistory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package sample.cafekiosk.spring.domain.history.mail; | ||
|
||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import sample.cafekiosk.spring.domain.BaseEntity; | ||
|
||
import javax.persistence.Entity; | ||
import javax.persistence.GeneratedValue; | ||
import javax.persistence.GenerationType; | ||
import javax.persistence.Id; | ||
|
||
@Getter | ||
@NoArgsConstructor | ||
@Entity | ||
public class MailSendHistory extends BaseEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
private String fromMail; | ||
|
||
private String toEmail; | ||
private String subject; | ||
private String content; | ||
|
||
@Builder | ||
private MailSendHistory(String fromMail, String toEmail, String subject, String content) { | ||
this.fromMail = fromMail; | ||
this.toEmail = toEmail; | ||
this.subject = subject; | ||
this.content = content; | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
src/main/java/sample/cafekiosk/spring/domain/history/mail/MailSendHistoryRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package sample.cafekiosk.spring.domain.history.mail; | ||
|
||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface MailSendHistoryRepository extends JpaRepository<MailSendHistory, Long> { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
7 changes: 7 additions & 0 deletions
7
src/main/java/sample/cafekiosk/spring/domain/order/OrderRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,15 @@ | ||
package sample.cafekiosk.spring.domain.order; | ||
|
||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.data.jpa.repository.Query; | ||
import org.springframework.stereotype.Repository; | ||
|
||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
|
||
@Repository | ||
public interface OrderRepository extends JpaRepository<Order, Long> { | ||
|
||
@Query("select o from Order o where o.registredDateTime >= ?1 and o.registredDateTime < ?2 and o.orderStatus = ?3") | ||
List<Order> findOrdersBy(LocalDateTime startDateTime, LocalDateTime endDateTime, OrderStatus orderStatus); | ||
} |
109 changes: 109 additions & 0 deletions
109
src/test/java/sample/cafekiosk/spring/api/service/order/OrderStatisticsServiceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package sample.cafekiosk.spring.api.service.order; | ||
|
||
import org.junit.jupiter.api.AfterEach; | ||
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 org.springframework.boot.test.mock.mockito.MockBean; | ||
import sample.cafekiosk.spring.client.mail.MailSendClient; | ||
import sample.cafekiosk.spring.domain.history.mail.MailSendHistory; | ||
import sample.cafekiosk.spring.domain.history.mail.MailSendHistoryRepository; | ||
import sample.cafekiosk.spring.domain.order.Order; | ||
import sample.cafekiosk.spring.domain.order.OrderRepository; | ||
import sample.cafekiosk.spring.domain.order.OrderStatus; | ||
import sample.cafekiosk.spring.domain.orderproduct.OrderProductRepository; | ||
import sample.cafekiosk.spring.domain.product.Product; | ||
import sample.cafekiosk.spring.domain.product.ProductRepository; | ||
import sample.cafekiosk.spring.domain.product.ProductType; | ||
|
||
import java.time.LocalDate; | ||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.mockito.ArgumentMatchers.any; | ||
import static org.mockito.Mockito.when; | ||
import static sample.cafekiosk.spring.domain.product.ProductSellingStatus.SELLING; | ||
import static sample.cafekiosk.spring.domain.product.ProductType.HANDMADE; | ||
|
||
@SpringBootTest | ||
class OrderStatisticsServiceTest { | ||
|
||
@Autowired | ||
private OrderStatisticsService orderStatisticsService; | ||
|
||
@Autowired | ||
private OrderProductRepository orderProductRepository; | ||
|
||
@Autowired | ||
private OrderRepository orderRepository; | ||
|
||
@Autowired | ||
private ProductRepository productRepository; | ||
|
||
@Autowired | ||
private MailSendHistoryRepository mailSendHistoryRepository; | ||
|
||
@MockBean | ||
private MailSendClient mailSendClient; | ||
|
||
@AfterEach | ||
void tearDown() { | ||
orderProductRepository.deleteAllInBatch(); | ||
orderRepository.deleteAllInBatch(); | ||
productRepository.deleteAllInBatch(); | ||
mailSendHistoryRepository.deleteAllInBatch(); | ||
} | ||
|
||
@DisplayName("결제완료 주문들을 조회하여 매출 통계 메일을 전송한다.") | ||
@Test | ||
void test() { | ||
// given | ||
LocalDateTime now = LocalDateTime.of(2023, 3, 5, 0, 0); | ||
Product product1 = createProduct(HANDMADE, "001", 1000); | ||
Product product2 = createProduct(HANDMADE, "002", 2000); | ||
Product product3 = createProduct(HANDMADE, "003", 3000); | ||
List<Product> products = List.of(product1, product2, product3); | ||
productRepository.saveAll(products); | ||
|
||
Order order1 = createPaymentCompletedOrder(LocalDateTime.of(2023, 3, 4, 23, 59, 59), products); | ||
Order order2 = createPaymentCompletedOrder(now, products); | ||
Order order3 = createPaymentCompletedOrder(LocalDateTime.of(2023, 3, 6, 23, 59, 59), products); | ||
Order order4 = createPaymentCompletedOrder(LocalDateTime.of(2023, 3, 6, 0, 0), products); | ||
|
||
// stubbing | ||
when(mailSendClient.sendEmail(any(String.class), any(String.class), any(String.class), any(String.class))) | ||
.thenReturn(true); | ||
|
||
// when | ||
boolean result = orderStatisticsService.sendOrderStatisticsMail(LocalDate.of(2023, 3, 5), "[email protected]"); | ||
|
||
// then | ||
assertThat(result).isTrue(); | ||
|
||
List<MailSendHistory> histories = mailSendHistoryRepository.findAll(); | ||
assertThat(histories).hasSize(1) | ||
.extracting("content") | ||
.contains("총 매출 합계는 6000원입니다."); | ||
|
||
} | ||
|
||
private Order createPaymentCompletedOrder(LocalDateTime now, List<Product> products) { | ||
return orderRepository.save(Order.builder() | ||
.registeredDateTime(now) | ||
.orderStatus(OrderStatus.PAYMENT_COMPLETED) | ||
.products(products) | ||
.build()); | ||
} | ||
|
||
private Product createProduct(ProductType type, String productNumber, int price) { | ||
return Product.builder() | ||
.productNumber(productNumber) | ||
.type(type) | ||
.sellingStatus(SELLING) | ||
.name("메뉴 이름") | ||
.price(price) | ||
.build(); | ||
} | ||
} |
72 changes: 72 additions & 0 deletions
72
src/test/java/sample/cafekiosk/spring/domain/order/OrderRepositoryTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package sample.cafekiosk.spring.domain.order; | ||
|
||
import org.assertj.core.api.Assertions; | ||
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 org.springframework.transaction.annotation.Transactional; | ||
import sample.cafekiosk.spring.domain.product.Product; | ||
import sample.cafekiosk.spring.domain.product.ProductRepository; | ||
import sample.cafekiosk.spring.domain.product.ProductSellingStatus; | ||
import sample.cafekiosk.spring.domain.product.ProductType; | ||
|
||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
|
||
import static org.assertj.core.groups.Tuple.tuple; | ||
import static sample.cafekiosk.spring.domain.order.OrderStatus.INIT; | ||
import static sample.cafekiosk.spring.domain.product.ProductSellingStatus.*; | ||
import static sample.cafekiosk.spring.domain.product.ProductType.HANDMADE; | ||
|
||
@SpringBootTest | ||
@Transactional | ||
class OrderRepositoryTest { | ||
|
||
@Autowired | ||
private OrderRepository orderRepository; | ||
|
||
@Autowired | ||
private ProductRepository productRepository; | ||
|
||
@DisplayName("특정 두 시간 사이에 특정 주문상태에 해당하는 주문을 가져올 수 있다.") | ||
@Test | ||
void findOrdersBy() { | ||
// given | ||
Product product1 = createProduct("001", HANDMADE, "아메리카노", HOLD, 6000); | ||
Product product2 = createProduct("002", HANDMADE, "팥빙수", STOP_SELLING, 5000); | ||
Product product3 = createProduct("003", HANDMADE, "카페라떼", SELLING, 4000); | ||
productRepository.saveAll(List.of(product1, product2, product3)); | ||
|
||
orderRepository.save(Order.create(LocalDateTime.of(2023, 11, 1, 0, 0, 0), List.of(product1, product2))); | ||
orderRepository.save(Order.create(LocalDateTime.of(2023, 12, 1, 0, 0, 0), List.of(product2, product3))); | ||
orderRepository.save(Order.create(LocalDateTime.of(2024, 3, 3, 0, 0, 0), List.of(product2))); | ||
|
||
LocalDateTime startDateTime = LocalDateTime.of(2023, 10, 31, 0, 0, 0); | ||
LocalDateTime endDateTime = LocalDateTime.of(2024, 10, 31, 0, 0, 0); | ||
|
||
// when | ||
List<Order> result = orderRepository.findOrdersBy(startDateTime, endDateTime, INIT); | ||
|
||
// then | ||
Assertions.assertThat(result) | ||
.hasSize(3) | ||
.extracting("registredDateTime", "totalPrice", "orderStatus") | ||
.containsExactlyInAnyOrder( | ||
tuple(LocalDateTime.of(2023, 11, 1, 0, 0, 0), 11000, INIT), | ||
tuple(LocalDateTime.of(2023, 12, 1, 0, 0, 0), 9000, INIT), | ||
tuple(LocalDateTime.of(2024, 3, 3, 0, 0, 0), 5000, INIT) | ||
); | ||
} | ||
|
||
private Product createProduct(String productNumber, ProductType type, String productName, ProductSellingStatus productSellingStatus, int price) { | ||
return Product.builder() | ||
.productNumber(productNumber) | ||
.type(type) | ||
.sellingStatus(productSellingStatus) | ||
.name(productName) | ||
.price(price) | ||
.build(); | ||
} | ||
|
||
} |
Oops, something went wrong.