public void SavePaymentInfo(String paymentid, String status, String paytime, String ordername, int totalamount)
{
OffsetDateTime offsetDateTime = OffsetDateTime.parse(paytime);
Timestamp requestedAtTimestamp = Timestamp.from(offsetDateTime.toInstant());
Payment payment = new Payment(
paymentid,status,requestedAtTimestamp,ordername,totalamount ) ;
paymentRepository.save(payment) ;
}
해당 내용을 TEST 하기 위해, TEST CODE를 작성하였다.
@ExtendWith(MockitoExtension.class)
class PaymentServiceTest {
@Mock
private PaymentRepository paymentRepository;
@InjectMocks
private PaymentService paymentService ;
@Test
public void giveninfo_thensaveok()
{
// Given
String paymentid = "paymenttestid1";
String status = null;
String paytime = "2024-02-23T10:00:00Z";
String ordername = "테스트로사기";
int totalamount = 10000;
// When
//then
assertThrows(IllegalArgumentException.class, () -> {
paymentService.SavePaymentInfo(paymentid, status, paytime, ordername, totalamount);
});
}
}
SERVICE의 따라쟁이(MOCK을 쉽게 설명하기 위해 쓴 표현이다)를 만들고,
REPOSITORY의 따라쟁이도 만들었다.
(mock을 주로 사용해서 이를 extendwith로 받았다. 이는 jpa와 관련된 test이고, 실제로 저장시키고 싶지 않았기 때문.)
이 따라쟁이들로, ASSERTHROWS(이하를 행동하여, EXCEPTION이 THROWS 되어야 통과)
하는 코드를 작성하였으나, NULL관련 EXCEPTION이 발생하지 않았다.
사실 해당 TEST는 2가지 측면에서 의미가 없었다는 것을 깨달았는데
1. 비동기적으로 OPEN API가 전달한 정보를 그대로 사용하기 때문에, NULL 일 수 없다.
2. NULL 이 어떻게 어떻게 되더라도(어떻게 되는지는 상상이 안된다), DB에서 EXCEPTION이 발생한다.
*그렇다면, DB에서 저장은 되지 않고 그다음 검증 SEVICE로 넘어가는데, 검증 SERVICE에선 이 DATA를 그대로 받아서 사용하기 때문에 이때 NULL인 FIELD를 검증하다 오류가 난다.
하지만, 어떤 경우일진 모르지만 null을 받아와 db에 결제정보를 저장하지 않고 다음 service를 진행할 수도 있다고 판단하여, 해당 내용을 변경하였다.
public void SavePaymentInfo(String paymentid, String status, String paytime, String ordername, int totalamount)
{
if (paymentid == null || status == null || paytime == null || ordername == null) {
throw new IllegalArgumentException("Payment 정보에 null 값이 포함되어 있습니다.");
}
OffsetDateTime offsetDateTime = OffsetDateTime.parse(paytime);
Timestamp requestedAtTimestamp = Timestamp.from(offsetDateTime.toInstant());
Payment payment = new Payment(
paymentid,status,requestedAtTimestamp,ordername,totalamount ) ;
paymentRepository.save(payment) ;
}
검증 SERVICE
TEST 해야할 내용은 , 1. 악의적인 공격으로 FRONT의 요청과 검증이 다를때 잘 동작하나
(통합 TEST로 검증할 수 없었다)
2. 결제 취소 요청을 보냈는데 문제가 생기면, LOG(관리자 호출 기능을 가정)가 잘 등장하고 BAD REQUEST를 잘 보내는지.
이렇게 확인해 보도록 하겠다.
결제 취소 실패시.
결제 취소와 결제 취소 실패 모두 같은 RESPONSE를 보낸다.
(이는 두 요청의 경우 모두 용납되어선 안되기 때문)
해당 과정에서 PORTONE API가 잘못된 요청을 주었을때 로그로 관리자를 호출하는 부분이 있는데,
이떄 해당 로그를 확인하는 것이 불가능. (비동기 작업이라 완료되었음이 확실하지 않아 종료 전 검증 가능성)
해결 방안
- ERROR를 MOCK으로 생성하여, 최종적인 결과 RESPONSE도 예측한 대로 잘 ERROR가 오는지 확인.
ERROR를 MOCK으로 응답하는 구조로 TEST
- 비동기적 구조는 , 작업의 완전 종료라는 개념이 모호하기 때문에 SUBSCRIBE 내부에서 진행하는 일을 밖으로 가져올 수 없다. (그러므로 TEST가 어렵다)
1-2. 그러므로, 비동기적 구조에서 ( 특히 OPEN API와의 통신 시) 설계시엔 동일응답을 정말 특이한 경우 아니고선 지양하고, TEST시 확인할 수 있는 RESPONSE를 설계하는 것에 주의하자.
@Mock
private WebClient webClient;
@Mock
private Logger logger;
@InjectMocks
private PurchaseService purchaseService ;
이런 사세한 부분도 까먹지 말자. 비동기의 TEST는 주의해야할 부분이 많다.
'프로젝트 > 장애인 PT 플랫폼, PTFD' 카테고리의 다른 글
DELETE , UPDATE 쿼리 관련 동시성 문제 (0) | 2024.03.30 |
---|---|
결제 과정 완료 (1) | 2024.02.27 |
SERVICE/CONTROLLER단 분할, 그에 따른 비동기적 형태 변경 (0) | 2024.02.23 |
FRONT에서의 결제 + 결제 정보 저장 (0) | 2024.02.22 |
Portone을 활용한 수기 결제(백엔드 단에 전 권한 이임) (0) | 2024.02.21 |