디지털 변화를 겪고 있는 기업들은 종종 수십 년 된 COBOL 메인프레임에서 IBM z/OS 시스템으로 사명-critical 핵심 뱅킹 거래가 계속 처리되는 복잡한 "브라운필드" 환경에서 운영됩니다. 동시에, 고객-facing 온보딩 및 서비스 흐름은 점점 더 현대의 React 기반 웹 포털과 모바일 애플리케이션에서 처리됩니다. 이러한 기술적 분기점은 QA 팀이 필수적으로 무결성 오류 없는 데이터 흐름과 트랜잭션 일관성을 보장해야 하므로 상당한 검증 문제를 야기합니다.
전통적으로 이러한 환경에서의 자동화 노력은 전문 팀이 메인프레임 터미널 에뮬레이션(예: Jagacy 또는 Extra!), 일반 UI 자동화(Selenium 또는 Cypress) 및 API 검증(Rest-Assured 또는 Postman) 등을 위한 별도의 도구 세트를 유지하면서 격리되는 경향이 있습니다. 이러한 단편화는 비기술적 비즈니스 분석가가 요구 사항을 검토하거나 검증할 수 없는 매우 기술적인 전문 용어로 작성된 취약한 통합 스위트를 초래합니다. 또한, 테스트가 실행 중에 실패하면 재앙적인 데이터 무결성 문제가 자주 발생하여, 메인프레임 계좌가 생성되는 동안 해당 웹 포털의 검증이 완료되지 않아, 다운스트림 환경이 고아 테스트 데이터로 오염될 수 있습니다.
이 특정 질문은 복잡한 "신규 고객 온보딩" 워크플로우를 검증하기 위해 애쓰고 있는 한 Fortune 500 금융 서비스 회사에서 나왔습니다. 이 워크플로우는 모바일 React 애플리케이션, Kafka 이벤트 버스, Java 마이크로서비스 계층 및 IBM z/OS 메인프레임에서의 최종 계정 프로비저닝을 포함했습니다. 조직은 이러한 기술적 간극을 메우면서 현대 DevOps 파이프라인의 민첩성을 유지할 수 있는 통합 자동화 전략이 필요했습니다. 문제가 더욱 복잡해진 것은 비즈니스 분석가가 각 시스템의 기본 기술 구현을 이해하지 않아도 테스트 시나리오를 작성하고 이해할 수 있어야 한다는 필요성이었습니다.
핵심 도전 과제는 동기화된 웹 자동화와 3270 메인프레임의 블록 모드 터미널 에뮬레이션 간의 기본적인 임피던스 불일치에 있으며, 이는 즉각적인 DOM 업데이트와 이벤트 기반 상호작용을 기대합니다. RESTful API는 상태 없는 요청-응답 패러다임 내에서 작업하여 터미널 세션에 내재된 세션 연속성을 결여합니다. 이러한 아키텍처 스타일을 연결하기 위해서는 높은 수준의 비즈니스 행동을 시스템 특정 명령으로 변환할 수 있는 추상화 계층이 필요하며, 테스트 시나리오에 기술적 구현 세부 사항이 누출되지 않도록 해야 합니다.
비즈니스 분석가들이 테스트 단계를 작성하는데 사용하며 비즈니스 분석가와 기술 이해관계자 간의 커뮤니케이션 수단으로서 DSL을 유지하는 것은 매우 어렵습니다. 웹 요소는 일반적으로 CSS 선택자나 XPath 표현식을 사용하여 식별되고, API 검증은 JSON 경로 주장 및 스키마 검증에 의존하며, 메인프레임 상호작용은 필드 좌표, 화면 레이블 또는 F1 또는 Enter와 같은 특정 키 시퀀스에 의존합니다. 강력한 추상화 전략이 없다면 DSL은 기술적 로케이터 및 시스템 특정 전문 용어로 어지럽혀져 그 목적을 상실하게 됩니다.
더욱이 이러한 분산 시스템 간의 진정한 트랜잭션 무결성을 보장하려면 테스트 프레임워크 아키텍처 내에서 사가 또는 보상 트랜잭션 패턴을 직접 구현해야 하며, 이는 메인프레임의 2단계 커밋 프로토콜이나 분산 트랜잭션 관리자에 대한 고유 훅(Hook)이 부족할 때는 간단하지 않습니다. 웹 포털에서 테스트 실패가 발생하여 이미 메인프레임 트랜잭션이 커밋된 경우, 프레임워크는 명시적 롤백 절차를 유도하여 환경 일관성을 복원할 수 있는 지능과 능력을 가져야 합니다. 이는 표준 try-catch 블록을 훨씬 초과하는 정교한 상태 추적 및 오류 처리 메커니즘을 필요로 합니다.
마지막으로 자동화 프레임워크는 테스트 스크립트에 민감한 자격 증명을 직접 포함하지 않고 다양한 인증 메커니즘을 안전하게 처리해야 합니다. 웹 포털은 종종 다단계 인증(MFA)과 함께 현대 OAuth2 또는 SAML 흐름을 사용하며, REST API는 API 키 또는 JWT 토큰에 의존하고 레거시 메인프레임은 정적 사용자 프로필을 사용하여 RACF 또는 ACF2 공급자에 대해 인증합니다. 보안 자세를 유지하면서 원활한 교차 시스템 인증을 가능하게 하는 중앙 집중형 암호화 자격 증명 금고와 환경 특정 주입 기능이 필수적입니다.
이러한 복잡성 해결을 위해 프레임워크는 육각형 아키텍처(포트 및 어댑터) 패턴을 사용하여 테스트 도메인 논리와 외부 시스템 상호작용 간에 엄격한 분리를 적용해야 합니다. enterCustomerData(), verifyAccountCreation(), rollbackTransaction()와 같은 고수준 도메인 메소드를 선언하는 추상 ApplicationDriver 포트 인터페이스를 정의하세요. 이 인터페이스는 DSL 계층(예: Cucumber 단계 정의 또는 SpecFlow 바인딩)이 상호작용할 수 있는 유일한 계약으로 작용하며, 구현 세부 사항으로부터 완전한 격리를 보장합니다.
구체적인 어댑터 구현은 시스템 특정 기술적 세부 사항을 처리합니다: SeleniumWebAdapter는 포트 메소드를 브라우저 상호작용으로 변환하고, RestAssuredAdapter는 HTTP 호출을 실행하고 JSON 응답을 파싱하며, HllapiMainframeAdapter는 High-Level Language API를 이용하여 키를 전송하고 화면 버퍼를 읽고 3270 에뮬레이터에서 필드 내용을 검증합니다. 각 어댑터는 자체 재시도 로직, 명시적 대기 메커니즘 및 해당 기술 스택에 적합한 오류 처리 전략을 캡슐화합니다. 어댑터가 상태를 수정하는 작업을 성공적으로 완료하면 원시 데이터 타입을 반환하는 대신 중앙 TestEventBus에 도메인 이벤트(예: AccountCreatedEvent)를 게시합니다.
트랜잭션 무결성을 위해 테스트 사가 오케스트레이터를 구현하여 테스트 시나리오 동안 실행된 모든 CompensableAction 객체의 정렬된 로그를 유지합니다. 워크플로의 어느 단계에서든 예외가 발생하면, 오케스트레이터는 자동으로 성공적인 행동의 compensate() 메소드를 역순으로 실행하여 메인프레임 계정을 삭제하거나 API 예약을 무효화하는 보상 트랜잭션을 실행합니다. 이 패턴은 테스트 환경이 테스트 중간에 실패할 경우에도 깨끗하게 유지되도록 보장하며, 기존의 종단 간 스위트에서 오염된 데이터를 모으는 것을 방지합니다.
상당히 이질적인 스택 간의 상태 관리는 TestContext를 1급 시민으로 처리하여 ThreadLocal<DomainContext>를 활용하여 원시 문자열 대신 풍부한 도메인 객체를 저장하여 테스트 단계 간의 긴밀한 결합을 방지합니다. React 어댑터는 컨텍스트 내에 CustomerProfile 객체를 구성할 수 있으며, 메인프레임 어댑터는 이후에 이를 검색하여 워크플로의 해당 부분을 수행합니다. 이 접근 방식은 DSL이 기술 식별자가 아닌 비즈니스 엔터티에 집중하도록 보장합니다.
이 구성 요소들을 연결하기 위해 Google Guava EventBus와 같은 경량 메시징 버스 또는 반응형 스트림을 활용하여 어댑터가 직접 메소드 호출 없이 상태 변경을 통신할 수 있도록 하여 메인프레임 흐름과 웹 검증 흐름을 분리합니다. HllapiMainframeAdapter가 계정을 성공적으로 생성하면, 계정 세부 정보를 포함하는 이벤트를 게시하며, SeleniumWebAdapter는 적절한 확인 화면으로 자동으로 탐색합니다. 이 테스트 프레임워크 내의 이벤트 기반 접근 방식은 현대 마이크로서비스 아키텍처를 반영하며, 개별 시스템 인터페이스가 변경될 때 유지 보수비용을 크게 줄입니다.
// 포트 인터페이스 정의 public interface BankingDriver { void enterCustomerData(Customer customer); AccountDetails submitAccountCreation(); void verifyAccountInPortal(AccountDetails account); void rollbackAccountCreation(AccountDetails account); } // HLLAPI를 사용하는 메인프레임 어댑터 public class MainframeAdapter implements BankingDriver { private final HllapiWrapper hllapi; private final EventBus eventBus; @Override public AccountDetails submitAccountCreation() { hllapi.sendKey("@E"); // Enter 키 시뮬레이션 waitForScreen("Account Created"); String accountId = hllapi.getTextByLabel("Account Number:"); AccountDetails details = new AccountDetails(accountId); eventBus.post(new AccountCreatedEvent(details)); return details; } @Override public void rollbackAccountCreation(AccountDetails account) { hllapi.sendKeys("DELETE " + account.getId()); hllapi.sendKey("@E"); verifyScreen("Deletion Confirmed"); } } // 트랜잭션 무결성을 위한 사가 오케스트레이터 public class TestSagaOrchestrator { private final List<CompensableAction> executedActions = new ArrayList<>(); public void execute(Runnable action, Runnable compensation) { try { action.run(); executedActions.add(new CompensableAction(action, compensation)); } catch (Exception e) { compensate(); throw new TestFailureException(e); } } private void compensate() { Collections.reverse(executedActions); for (CompensableAction action : executedActions) { try { action.compensate(); } catch (Exception ex) { publishToDeadLetterQueue(action, ex); } } } }
2022년 디지털 변환을 겪고 있는 글로벌 보험 제공업체와의 컨설팅 업무 중, 이러한 정확한 도전을 나타내는 "First Notice of Loss" (FNOL) 비즈니스 프로세스를 만나게 되었습니다. 이 워크플로우는 보험 가입자가 React Native 모바일 애플리케이션을 통해 사고 사진을 업로드하여 클레임을 제출하고, 여기에 따라 Python 기반의 기계 학습 마이크로서비스가 손상 평가와 사기 탐지를 수행한 후, 최종적으로 재정 예비를 할당하고 정책 보장을 검증하기 위해 레거시 Unisys 메인프레임 시스템을 업데이트해야 하는 것을 요구했습니다. 기존의 자동화 전략은 모바일 앱을 위한 Cypress, API를 위한 Pytest, 메인프레임 터미널 에뮬레이션을 위한 Jagacy라는 세 개의 서로 소통하지 않는 스위트에 의존하고 있었습니다.
단절된 접근 방식은 팀 간의 클레임 번호를 공유 Excel 스프레드시트를 사용하여 수동 상관시키게 하였고, 환경 오염은 회귀 주기 동안 심각한 장애물이 되었습니다. 위기 순간은 모바일 네트워크 타임아웃이 발생하여 메인프레임에서 이미 $50,000의 예비 할당이 커밋된 후 테스트가 실패하였고, 그로 인해 재정 데이터가 불일치 상태에 놓여 메인프레임 시스템 프로그래머가 수동으로 네 시간의 정리가 필요했습니다. 이 사건은 팀의 "깨끗한 환경" 정책을 직접 위반했으며, CI/CD 파이프라인을 하루 전체 차단했습니다.
우리는 향후 발생을 방지하기 위해 세 가지 잠재적인 해결 전략을 평가했습니다. 첫 번째 옵션은 메인프레임 트랜잭션을 수동으로 되돌리기 위한 테스트 후 데이터베이스 정리 스크립트를 작성하는 것이었지만, 보안 정책이 프로덕션과 유사한 UAT 메인프레임 환경에 대한 직접 SQL 접근을 금지하여 거부되었습니다. 두 번째 접근은 테스트 실행을 직렬화하기 위한 비관적 잠금 메커니즘을 가진 공유 테스트 데이터 풀을 구현하는 것이었지만, 이는 스위트 실행 시간을 20분에서 4시간 이상으로 증가시켜 CI/CD에서 병렬 처리의 이점을 완전히 무너뜨릴 것이었습니다. 세 번째 전략, 즉 우리가 궁극적으로 선택한 전략은, 테스트 자동화 프레임워크 내에 사가 패턴을 구현하여 애플리케이션의 최종 일관성 모델을 반영하면서 수백 개의 테스트를 병렬로 실행할 수 있는 능력을 보존하는 것이었습니다.
구현된 솔루션은 모바일 및 메인프레임 어댑터에 의해 수행된 모든 작업을 가로채는 ClaimSaga 오케스트레이터를 도입했습니다. 모바일 어댑터가 네트워크 타임아웃으로 인해 StaleElementReferenceException을 발생시킬 경우, 사가는 즉시 클레임 ID를 활용하여 메인프레임 어댑터의 reverseReserveAllocation() 보상 트랜잭션을 트리거했습니다. 이 자동 롤백 메커니즘은 환경 데이터 오염을 98% 감소시켰고, 팀이 고아 재정 기록을 만드는 두려움 없이 Jenkins 파이프라인에서 500개의 병렬 스레드를 자신 있게 실행할 수 있도록 했습니다.
테스트 신뢰성이 급격히 개선됨에 따라 QA 팀은 수동 데이터 정리에서 탐색적 테스트 및 엣지 케이스 분석으로 초점을 전환할 수 있었습니다. 비즈니스 분석가는 이제 주어진 보험 가입자가 주요 사고를 보고하고, 사진이 업로드되지만 AI 평가 서비스가 타임아웃될 경우, 재정 예비금이 할당되어서는 안 된다와 같이 평이한 영어로 작성된 테스트 시나리오를 작성하고 검토할 수 있게 되었습니다. 이는 자동화 스위트가 모든 세 기술 계층에 걸쳐 복잡한 비즈니스 규칙을 반영하는 정확한 생생한 문서 역할을 한다는 것을 보장했습니다.
에뮬레이터와 웹 포털 간의 세션 상태 지속성을 어떻게 처리하여 어댑터 간의 긴밀한 결합을 만들지 않습니까?
초보 지원자는 종종 이 문제를 해결하기 위해 단계 정의 메소드에서 원시 세션 식별자 또는 데이터베이스 기본 키를 직접 반환하려고 시도하여, 단계 B가 단계 A가 특정 문자열 값을 명시적으로 반환하기 전까지 실행될 수 없는 취약한 의존성을 생성합니다. 이 접근 방식은 본질적으로 도메인 주도 설계 원칙을 깨뜨리며, 비즈니스 가독성이 있는 Gherkin 단계를 기술적 순서상에서의 엄격한 순서로 강제하게 만듭니다. 게다가 구현 세부 사항이 DSL 계층에 누출되어 기술 식별자가 형식이 변경되면 테스트가 취약해집니다.
강력한 아키텍처 솔루션은 테스트 실행 기간 동안의 임시 레지스트리 역할을 하는 시나리오 컨텍스트 또는 테스트 데이터 컨텍스트를 구현하여, 일반적으로 ThreadLocal<Map<Class<?>, Object>>를 사용하여 병렬 실행 중 스레드 안전성을 보장합니다. 어댑터는 DSL 계층에 원시 값을 반환하지 않습니다. 대신 그들은 이 컨텍스트에 강력하게 입력된 도메인 이벤트 또는 객체를 게시합니다. 예를 들어, 메인프레임 어댑터가 계정을 성공적으로 생성하면, 전체 계정 엔티티를 포함하는 AccountCreatedEvent를 게시하며, 이후 웹 어댑터는 이벤트 버스를 청취하거나 컨텍스트를 쿼리하여 이를 검색합니다.
이벤트 기반 접근 방식은 DSL 계층이 데이터의 기원에 대해 완전히 무관하게 유지하도록 보장합니다. 정책 번호가 녹색 화면에서 스크랩되었든 JSON 응답으로 반환되었든 관계없이 말입니다. 추상화에 의존함으로써, 프레임워크는 의존성 역전 원칙을 따릅니다. 이는 개별 어댑터가 비즈니스 가독성이 있는 테스트 시나리오에 영향을 주지 않고 리팩터링되거나 교체될 수 있도록 하여 장기적인 유지 관리 비용을 상당히 줄입니다.
어떤 특정 메커니즘이 보상 트랜잭션이 실패하지 않도록 방지하여 시스템이 불일치 상태에 놓이게 만들지 않습니까?
많은 주니어 엔지니어들은 보상 논리가 스스로 오류를 Encounter할 수 있는 주요 실패 모드를 간과합니다. 이러한 오류에는 메인프레임 레코드를 삭제하려고 할 때의 네트워크 타임아웃이나 레코드가 이미 배경 프로세스에 의해 수정된 경우의 검증 실패가 포함될 수 있습니다. 이 시나리오는 "독성 데이터" 축적을 초래하여 원래 작업은 성공했지만 롤백이 실패하고 테스트 환경이 영구적으로 손상된 상태에 남게 됩니다.
해결 방법은 멱등성 보상 작업을 구현하여 안전하게 여러 번 재시도할 수 있도록 설계된 작업으로, 중복 삭제 오류를 일으키지 않습니다. 이러한 작업은 또한 일시적인 인프라 실패를 우아하게 처리하기 위해 지수 적정 회복 및 회로 차단자 패턴이 포함된 복원력 있는 재시도 메커니즘과 결합되어야 합니다. 모든 재시도 시도가 소모되면, 프레임워크는 실패한 보상 세부 사항을 지속 가능한 **데드 레터 큐(DLQ)**에 게시해야 합니다. 이 DLQ는 완전한 상관 관계 ID 및 스택 트레이스를 포함한 데이터베이스 테이블 또는 메시지 주제로 구현될 수 있습니다.
또한 보상을 시도하기 전에 현재 하위 시스템의 상태를 검증하기 위한 검증 게이트를 구현해야 합니다. 예를 들어, 메인프레임 계정이 존재하고, 잔액이 0이며, 최근 사용자 수정이 없음을 확인한 후에 삭제 명령을 발급합니다. 이후 밤마다 자동화된 조정 작업이 DLQ를 처리하여 이러한 고아 레코드를 수동으로 처리하면서, 테스트 환경이 스스로 수리하고 기존 데이터 오염으로 인해 중요한 회귀가 가려지지 않도록 보장합니다.
메인프레임의 좌표 기반 화면 스크래핑(HLLAPI)을 사용하는 것이 왜 부작용으로 간주되며, 화면 레이아웃이 불가피하게 변경될 때 유지 관리 오버헤드를 줄이기 위해 어떻게 추상화합니까?
지원자들은 자주 하드코딩된 행과 열 좌표, 예를 들어 getText(10, 45, 10)와 같이 10행, 45열에서 10자를 읽는 방법을 선호합니다. 이들은 초기 테스트 개발 중에 정의된 정밀하고 결정적이므로 이 접근 방식을 선호합니다. 그러나 이 전략은 매우 심각한 유지 관리 부담을 초래합니다. 메인프레임 애플리케이션은 자주 화면 수정을 겪으며, 새로운 필드가 삽입되어 모든 후속 좌표 오프셋이 이동하게 되고 전체 테스트 스위트가 경고 없이 무효화됩니다.
강력한 아키텍처 솔루션은 화면 객체 모델을 구현하여 논리적 필드 이름(예: ACCOUNT_NUMBER_FIELD)을 정적 좌표 대신 동적 검색 기준에 매핑합니다. HLLAPI 기능인 FindFieldPosition 또는 SearchField를 통해 사용 가능한 메인프레임 에뮬레이터의 필드 식별 기능을 활용하여 레이블과 연결된 텍스트(예: "Account Number:")로 필드를 찾습니다. 런타임 중 어댑터는 화면 버퍼에서 레이블 텍스트를 검색하고 해당 입력 필드에 대한 상대적 오프셋을 계산합니다. 화면 레이아웃이 변경되면, 레이블을 오프셋에 매핑하는 JSON 구성 파일만 업데이트하면 되고, 컴파일된 Java 코드는 수정할 필요가 없습니다.
더욱 큰 회복력을 위해 런타임 상호작용 시작 시 unprotected 필드 내용의 암호화 해시를 캡처하는 화면 해시 또는 체크섬 메커니즘을 구현합니다. 해시가 예상 베이스라인과 일치하지 않으면 프레임워크는 잘못된 위치에서 데이터를 읽으려고 시도하기 보다는 "화면 불일치" 오류로 빠르게 실패합니다. 이는 테스트가 엉터리 데이터를 가지고 진행되는 것을 방지하며, 즉시 자동화 팀에 구성 업데이트가 필요한 화면 변경을 경고합니다.