JSONMessage validation 단위테스트 추가 및 SystemKeys 버그 수정

- SystemKeys.isValidationEnabled() 하드코딩 버그 수정 (return false → return validationEnabled)
- init_json_validation.sql: EAI_UJSONTYPE_REQ1 레이아웃 전용 테스트 데이터 추가
- JSONMessageValidationTest: @DataJpaTest + H2 기반 JUnit 5 단위테스트 7개
  - 타입 불일치(INT/LONG/BIGDECIMAL 필드에 비숫자 입력) → MessageSetDataException 검증
  - BigDecimal 정수부/소수부 자릿수 초과 → InvalidDataTypeException 검증

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
curry772
2026-04-22 18:13:35 +09:00
parent c8a58fdf5b
commit ae629d51e6
3 changed files with 223 additions and 1 deletions
@@ -86,7 +86,7 @@ public class SystemKeys {
}
public static boolean isValidationEnabled() {
return false;
return validationEnabled;
}
public static boolean isAddDecimalPointEnabled() {
@@ -0,0 +1,213 @@
package com.eactive.eai.transformer;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.jdbc.Sql;
import com.eactive.eai.transformer.engine.TransformEngine;
import com.eactive.eai.transformer.function.jpa.TransformJPATestConfiguration;
import com.eactive.eai.transformer.message.InvalidDataTypeException;
import com.eactive.eai.transformer.message.Message;
import com.eactive.eai.transformer.message.MessageFactory;
import com.eactive.eai.transformer.message.MessageSetDataException;
/**
* JSONMessage 필드 validation 단위테스트
*
* 테스트 대상 레이아웃: EAI_UJSONTYPE_REQ1
* - INT_VALUE : INT, length=5, decimal=0
* - LONG_VALUE : LONG, length=10, decimal=0
* - BIG_VALUE : BIGDECIMAL, length=10, decimal=5 → 정수부 최대 4자리
* - BIG15_VALUE : BIGDECIMAL, length=15, decimal=0 → 정수부 최대 15자리
*
* 검증 시나리오
* 1) 타입 불일치 — 숫자형 필드에 비숫자 문자열 입력 시 setData() 에서 즉시 오류
* 2) 길이 초과 — BigDecimal 정수부/소수부 자릿수 초과 시 getData() 에서 오류
* (SystemKeys.TRANSFROMER_VALIDATION=true 필요)
*/
@DataJpaTest
@ContextConfiguration(classes = { TransformJPATestConfiguration.class })
@Sql({
"/com/eactive/eai/transformer/init_tseaitr06.sql",
"/com/eactive/eai/transformer/init_json_validation.sql"
})
@DisplayName("JSONMessage Validation 테스트")
class JSONMessageValidationTest {
@Autowired
TransformEngine engine;
@BeforeEach
void setUp() {
try {
if (!engine.isStarted()) {
engine.start();
}
} catch (Exception e) {
assumeTrue(false, "TransformEngine 시작 실패: " + e.getMessage());
}
}
@AfterEach
void tearDown() {
System.setProperty(SystemKeys.TRANSFROMER_VALIDATION, "false");
SystemKeys.reload();
}
// ─────────────────────────────────────────────────────────────────
// 1. 타입 불일치 테스트 — setData() 시점에 오류 발생
// ─────────────────────────────────────────────────────────────────
@Test
@DisplayName("INT 타입 필드에 비숫자 문자열 입력 → NumberFormatException")
void testIntFieldTypeError() {
String data = "{\"EAI_UJSONTYPE_REQ1\":{\"INT_VALUE\":\"abc\"}}";
Message msg = MessageFactory.getFactory().getMessage("EAI_UJSONTYPE_REQ1");
MessageSetDataException ex = assertThrows(
MessageSetDataException.class,
() -> msg.setData(data)
);
assertTrue(containsCause(ex, NumberFormatException.class),
"원인이 NumberFormatException이어야 합니다");
}
@Test
@DisplayName("LONG 타입 필드에 비숫자 문자열 입력 → NumberFormatException")
void testLongFieldTypeError() {
String data = "{\"EAI_UJSONTYPE_REQ1\":{\"LONG_VALUE\":\"not_a_number\"}}";
Message msg = MessageFactory.getFactory().getMessage("EAI_UJSONTYPE_REQ1");
MessageSetDataException ex = assertThrows(
MessageSetDataException.class,
() -> msg.setData(data)
);
assertTrue(containsCause(ex, NumberFormatException.class),
"원인이 NumberFormatException이어야 합니다");
}
@Test
@DisplayName("BIGDECIMAL 타입 필드에 비숫자 문자열 입력 → NumberFormatException")
void testBigDecimalFieldTypeError() {
String data = "{\"EAI_UJSONTYPE_REQ1\":{\"BIG_VALUE\":\"invalid_decimal\"}}";
Message msg = MessageFactory.getFactory().getMessage("EAI_UJSONTYPE_REQ1");
MessageSetDataException ex = assertThrows(
MessageSetDataException.class,
() -> msg.setData(data)
);
assertTrue(containsCause(ex, NumberFormatException.class),
"원인이 NumberFormatException이어야 합니다");
}
// ─────────────────────────────────────────────────────────────────
// 2. 숫자형 길이 초과 테스트 — getData() 시점에 오류 발생
// transformer.validation=true 설정 필요
// ─────────────────────────────────────────────────────────────────
@Test
@DisplayName("BIG_VALUE 정수부 초과(5자리 > 4자리 제한) → InvalidDataTypeException")
void testBigDecimalIntegerPartOverflow() throws Exception {
enableValidation();
// 정수부 5자리(12345) → 제한(4자리) 초과
String data = "{\"EAI_UJSONTYPE_REQ1\":{\"BIG_VALUE\":12345.12345}}";
Message msg = MessageFactory.getFactory().getMessage("EAI_UJSONTYPE_REQ1");
msg.setData(data);
InvalidDataTypeException ex = assertThrows(
InvalidDataTypeException.class,
() -> msg.getData()
);
assertTrue(containsMessage(ex, "Invalid decimal point format"),
"'Invalid decimal point format' 메시지가 포함되어야 합니다");
}
@Test
@DisplayName("BIG_VALUE 소수부 초과(6자리 > 5자리 제한) → InvalidDataTypeException")
void testBigDecimalFractionalPartOverflow() throws Exception {
enableValidation();
// 소수부 6자리(123456) → 제한(5자리) 초과
String data = "{\"EAI_UJSONTYPE_REQ1\":{\"BIG_VALUE\":1234.123456}}";
Message msg = MessageFactory.getFactory().getMessage("EAI_UJSONTYPE_REQ1");
msg.setData(data);
InvalidDataTypeException ex = assertThrows(
InvalidDataTypeException.class,
() -> msg.getData()
);
assertTrue(containsMessage(ex, "Invalid decimal point format"),
"'Invalid decimal point format' 메시지가 포함되어야 합니다");
}
@Test
@DisplayName("BIG15_VALUE 정수부 초과(16자리 > 15자리 제한) → InvalidDataTypeException")
void testBigDecimalIntegerOnlyOverflow() throws Exception {
enableValidation();
// 정수부 16자리 → 제한(15자리) 초과
String data = "{\"EAI_UJSONTYPE_REQ1\":{\"BIG15_VALUE\":1234567890123456}}";
Message msg = MessageFactory.getFactory().getMessage("EAI_UJSONTYPE_REQ1");
msg.setData(data);
InvalidDataTypeException ex = assertThrows(
InvalidDataTypeException.class,
() -> msg.getData()
);
assertTrue(containsMessage(ex, "Invalid decimal point format"),
"'Invalid decimal point format' 메시지가 포함되어야 합니다");
}
@Test
@DisplayName("BIG_VALUE 정상 범위(정수부 4자리 + 소수부 5자리) → 정상 처리")
void testBigDecimalWithinBounds() throws Exception {
enableValidation();
// 정수부 4자리 + 소수부 5자리 → 정상
String data = "{\"EAI_UJSONTYPE_REQ1\":{\"BIG_VALUE\":1234.12345}}";
Message msg = MessageFactory.getFactory().getMessage("EAI_UJSONTYPE_REQ1");
msg.setData(data);
String result = (String) msg.getData();
assertNotNull(result, "결과값이 null이 아니어야 합니다");
assertTrue(result.contains("BIG_VALUE"), "BIG_VALUE가 결과에 포함되어야 합니다");
}
// ─────────────────────────────────────────────────────────────────
// 유틸 메서드
// ─────────────────────────────────────────────────────────────────
private void enableValidation() {
System.setProperty(SystemKeys.TRANSFROMER_VALIDATION, "true");
SystemKeys.reload();
}
private boolean containsCause(Throwable e, Class<?> causeClass) {
Throwable t = e;
while (t != null) {
if (causeClass.isInstance(t)) return true;
t = t.getCause();
}
return false;
}
private boolean containsMessage(Throwable e, String keyword) {
Throwable t = e;
while (t != null) {
if (t.getMessage() != null && t.getMessage().contains(keyword)) return true;
t = t.getCause();
}
return false;
}
}
@@ -0,0 +1,9 @@
INSERT INTO tseaitr07 (loutname,loutptrnname,loutdesc,lastamndhms,eaibzwkdstcd,uapplname,sysintfacname,eaisevrdstcd,modfimgtstusdstcd,useyn,verinfo,author) VALUES
('EAI_UJSONTYPE_REQ1', 'JSON', 'JSON 타입 검증 테스트', '2026042210000000', 'TST', ' ', ' ', 'E', ' ', '1', '00001', 'admin');
INSERT INTO TSEAITR08 (loutname,loutitemname,loutitemserno,loutitemidname,parntloutitemidname,loutitemdesc,loutitemnodeptrnidname,loutitemptrnidname,loutitempathname,loutitemlencnt,loutitemrefinfo,loutitemrefinfo2,loutitemoccurptrndstcd,loutitemmaxoccurnoitm,loutitemminoccurnoitm,loutitembascval,loutitemmskyn,loutdptcnt,decptlencnt,loutitemrefptrnidname,loutitemmasklength,multilang,loutitemmaskoffset) VALUES
('EAI_UJSONTYPE_REQ1', 'EAI_UJSONTYPE_REQ1', 0, 9000, 0, 'JSON 타입 검증 테스트', 2201, 2100, NULL, 0, NULL, NULL, NULL, 0, 0, NULL, NULL, 1, 0, NULL, NULL, NULL, NULL),
('EAI_UJSONTYPE_REQ1', 'INT_VALUE', 1, 9001, 9000, 'INT 타입 필드', 2203, 2102, NULL, 5, NULL, NULL, NULL, 1, 1, NULL, 'N', 2, 0, 'Integer', 0, NULL, NULL),
('EAI_UJSONTYPE_REQ1', 'LONG_VALUE', 2, 9002, 9000, 'LONG 타입 필드', 2203, 2103, NULL, 10, NULL, NULL, NULL, 1, 1, NULL, 'N', 2, 0, 'Long', 0, NULL, NULL),
('EAI_UJSONTYPE_REQ1', 'BIG_VALUE', 3, 9003, 9000, 'BIGDECIMAL length=10 decimal=5', 2203, 2118, NULL, 10, NULL, NULL, NULL, 1, 1, NULL, 'N', 2, 5, 'BigDecimal', 0, NULL, NULL),
('EAI_UJSONTYPE_REQ1', 'BIG15_VALUE', 4, 9004, 9000, 'BIGDECIMAL length=15 decimal=0', 2203, 2118, NULL, 15, NULL, NULL, NULL, 1, 1, NULL, 'N', 2, 0, 'BigDecimal', 0, NULL, NULL);