This commit is contained in:
Yolando
2026-02-28 05:16:36 +07:00
parent 84c508d378
commit 53d14b8caf
2 changed files with 220 additions and 0 deletions

View File

@@ -0,0 +1,151 @@
package com.ando.dynamic_soa_mapper;
import com.ando.dynamic_soa_mapper.entity.Payment;
import com.ando.dynamic_soa_mapper.entity.SoaMappingConfig;
import com.ando.dynamic_soa_mapper.entity.Transaction;
import com.ando.dynamic_soa_mapper.repository.PaymentRepository;
import com.ando.dynamic_soa_mapper.repository.SoaMappingConfigRepository;
import com.ando.dynamic_soa_mapper.repository.TransactionRepository;
import com.ando.dynamic_soa_mapper.service.MappingEngineService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class) // Mengaktifkan Mockito
class MappingEngineServiceTest {
@Mock
private TransactionRepository transactionRepo;
@Mock
private PaymentRepository paymentRepo;
@Mock
private SoaMappingConfigRepository configRepo;
@InjectMocks
private MappingEngineService mappingEngineService;
private Transaction dummyTransaction;
private Payment dummyPayment;
@BeforeEach
void setUp() {
// Setup data dummy yang akan digunakan di setiap test
dummyPayment = new Payment();
dummyPayment.setId("PAY-123");
dummyPayment.setDebitAccountNo("1122334455");
dummyPayment.setCurrency("IDR");
dummyTransaction = new Transaction();
dummyTransaction.setId("TRX-123");
dummyTransaction.setPaymentId("PAY-123");
dummyTransaction.setAmount(new BigDecimal("1000.00"));
dummyTransaction.setStatus("SUCCESS");
}
@Test
void testConstructPayload_SuccessFlatMapping() {
// 1. Persiapkan rule mapping (Mock Database)
SoaMappingConfig config1 = createConfig("TLBF_ACC", "#payment.debitAccountNo", null, 1);
SoaMappingConfig config2 = createConfig("TLBF_AMT", "#transaction.amount * 5", null, 1);
// 2. Ajari Mockito cara membalas request
when(transactionRepo.findById("TRX-123")).thenReturn(Optional.of(dummyTransaction));
when(paymentRepo.findById("PAY-123")).thenReturn(Optional.of(dummyPayment));
when(configRepo.findByKotranAndStatusOrderByTargetFieldNmAsc(eq("1001"), eq("ACTIVE")))
.thenReturn(Arrays.asList(config1, config2));
// 3. Eksekusi Engine
Map<String, Object> payload = mappingEngineService.constructPayload("TRX-123", "1001");
// 4. Verifikasi Hasil
assertNotNull(payload);
assertEquals(2, payload.size());
assertEquals("1122334455", payload.get("TLBF_ACC"));
assertEquals(new BigDecimal("5000.00"), payload.get("TLBF_AMT")); // 1000 * 5
}
@Test
@SuppressWarnings("unchecked")
void testConstructPayload_SuccessNestedMappingDotNotation() {
// 1. Setup rule mapping nested (Notasi Titik)
SoaMappingConfig config1 = createConfig("header.msgId", "'MSG-' + #transaction.id", null, 1);
SoaMappingConfig config2 = createConfig("body.account.currency", "#payment.currency", null, 1);
when(transactionRepo.findById("TRX-123")).thenReturn(Optional.of(dummyTransaction));
when(paymentRepo.findById("PAY-123")).thenReturn(Optional.of(dummyPayment));
when(configRepo.findByKotranAndStatusOrderByTargetFieldNmAsc(eq("1002"), eq("ACTIVE")))
.thenReturn(Arrays.asList(config1, config2));
// 2. Eksekusi
Map<String, Object> payload = mappingEngineService.constructPayload("TRX-123", "1002");
// 3. Verifikasi hierarki JSON (Nested Map)
assertTrue(payload.containsKey("header"));
Map<String, Object> headerMap = (Map<String, Object>) payload.get("header");
assertEquals("MSG-TRX-123", headerMap.get("msgId"));
assertTrue(payload.containsKey("body"));
Map<String, Object> bodyMap = (Map<String, Object>) payload.get("body");
Map<String, Object> accountMap = (Map<String, Object>) bodyMap.get("account");
assertEquals("IDR", accountMap.get("currency"));
}
@Test
void testConstructPayload_MandatoryFieldThrowsException() {
// Setup rule di mana data aslinya kosong, tapi isMandatory = 1
dummyTransaction.setStatus(null); // Kita buat status jadi null
SoaMappingConfig config1 = createConfig("TLBF_STS", "#transaction.status", null, 1);
when(transactionRepo.findById("TRX-123")).thenReturn(Optional.of(dummyTransaction));
when(paymentRepo.findById("PAY-123")).thenReturn(Optional.of(dummyPayment));
when(configRepo.findByKotranAndStatusOrderByTargetFieldNmAsc(eq("1003"), eq("ACTIVE")))
.thenReturn(Arrays.asList(config1));
// Harus melempar RuntimeException karena mandatory field null
Exception exception = assertThrows(RuntimeException.class, () -> {
mappingEngineService.constructPayload("TRX-123", "1003");
});
assertTrue(exception.getMessage().contains("Field Mandatory gagal di-mapping"));
}
@Test
void testConstructPayload_FallbackToDefaultValue() {
// Setup rule dengan SpEL error/null, tapi punya default value
SoaMappingConfig config1 = createConfig("TLBF_PROMO", "#transaction?.promoCode", "NO_PROMO", 1);
when(transactionRepo.findById("TRX-123")).thenReturn(Optional.of(dummyTransaction));
when(paymentRepo.findById("PAY-123")).thenReturn(Optional.of(dummyPayment));
when(configRepo.findByKotranAndStatusOrderByTargetFieldNmAsc(eq("1004"), eq("ACTIVE")))
.thenReturn(Arrays.asList(config1));
Map<String, Object> payload = mappingEngineService.constructPayload("TRX-123", "1004");
// Harus menggunakan default value
assertEquals("NO_PROMO", payload.get("TLBF_PROMO"));
}
// Helper method agar code rapi
private SoaMappingConfig createConfig(String targetFieldNm, String expressionRule, String defaultValue, Integer isMandatory) {
SoaMappingConfig config = new SoaMappingConfig();
config.setTargetFieldNm(targetFieldNm);
config.setExpressionRule(expressionRule);
config.setDefaultValue(defaultValue);
config.setIsMandatory(isMandatory);
return config;
}
}