목록으로
세금 환급 자동화 : AI-driven UI 테스트 자동화 일지
Blog2026.01.04

세금 환급 자동화 : AI-driven UI 테스트 자동화 일지

요약

토스인컴 QA Manager는 복잡하고 변화가 잦은 세금환급 서비스의 E2E 테스트 자동화 난관에 직면하여, AI를 적극 활용한 'AI-driven 테스트 자동화' 실험을 5개월간 진행했습니다.
Claude Sonnet 4.5를 SDET Agent 등으로 활용하여 Page Object Model 도입, 약관 처리 유틸 개발, React UI 안정화 전략 수립 등 핵심적인 테스트 코드 작성 및 아키텍처링을 AI가 주도했습니다.
이 실험을 통해 AI 3명과 사람 1명이 4~5명 규모의 자동화 팀에 상응하는 성과를 달성했으며, QA 전문가는 코딩 대신 문제 정의, AI와의 협업 및 결과 검증에 집중하며 QA 역량이 증폭됨을 입증했습니다.

상세 내용

이 보고서는 토스인컴의 QA Manager 정수호가 세금 환급 서비스의 복잡한 E2E 테스트 자동화 문제를 AI 기반으로 해결한 5개월간의 실험 경험을 담고 있습니다. 토스인컴의 세금 환급 서비스는 연말정산, 현금영수증, 세금비서, 숨은환급찾기 등 네 가지 주요 서비스로 구성되어 있으며, 각각 다른 UX와 인증 방식을 사용하고 수십 가지의 공제 항목을 포함합니다. 또한, 실험 그룹, 약관 종류, 홈택스 스크래핑 서버 상태 등에 따라 테스트해야 할 플로우 조합이 급증하여, 한 명의 QA 인력으로는 감당하기 어려운 상황이었습니다. 기존 방식으로는 E2E 테스트 하나를 만드는데 4~8시간이 소요되었고, UI나 정책 변경 시마다 테스트를 수정해야 하는 높은 유지보수 비용이 발생했습니다. 이러한 문제에 직면하여 저자는 "QA가 코드를 직접 치지 않아도 된다면 어떨까?"라는 질문을 던지며 AI를 활용한 자동화 팀 구성 실험을 시작했습니다. 결론적으로, 'AI 3명 + 사람 1명'으로 구성된 팀이 4~5명 규모의 자동화 팀이 낼 만한 성과를 달성했습니다.

AI를 도입하게 된 주된 이유는 세금 환급 서비스 자동화가 일반적인 웹 서비스보다 훨씬 높은 난이도를 가졌기 때문입니다. 이는 크게 세 가지 복합적인 요인 때문입니다:

  • 복잡한 플로우: 환급 플로우는 평균 15~20단계를 넘어서며, 각 단계는 로그인(내부 인증 시스템), 공제 선택(정책 엔진), 스크래핑(외부 공공기관 API), 환급 금액 계산(엔진), 결제(페이 연동) 등 서로 다른 시스템 특성에 의존합니다. 이는 마치 '장거리 릴레이'처럼 작동하여 단 한 단계라도 타이밍이 어긋나거나 외부 시스템 상태가 달라지면 전체 플로우가 실패할 수 있습니다. 특히 React 기반 UI의 자연스러운 애니메이션이나 오버레이는 E2E 테스트에서 클릭 미스, 전환 실패, 대기 타임아웃으로 이어지기 쉽습니다.
  • 잦고 큰 UI/정책 변경: 사용자에게는 사소해 보이는 버튼 문구 변경, 질문 추가, 스크래핑 UI 개편 등이 자동화 테스트에서는 시나리오 전체를 다시 구성해야 하는 대규모 변경으로 작용합니다. 이는 Playwright와 같은 자동화 도구의 셀렉터, 대기 전략, 분기 흐름을 모두 다시 손봐야 하는 수준으로, 하드코딩된 테스트의 안정성을 저해합니다.
  • 불안정한 환경: 실험 그룹에 따른 화면 차이, 스크래핑 탭의 열림/닫힘으로 인한 Target closed 에러, 환경별 도메인 차이 등 불안정한 환경 요인이 많아, 사람 중심의 개발 방식으로는 35개 시나리오를 모두 자동화하기 어려웠습니다.
  • 이러한 문제 해결을 위해 "AI가 코드를 짜고, 사람은 문제 정의와 품질 검증에 집중한다"는 전략이 채택되었습니다. 사용된 주요 AI 도구는 다음과 같습니다.

    * Claude Sonnet 4.5 (Claude Code): 메인 개발자 역할을 담당하여 테스트 코드, 유틸 함수, 리팩토링, 문서화 등을 수행했습니다. Claude는 SDET (Software Development Engineer in Test) Agent, Documentation Specialist, Git Master의 세 가지 페르소나로 활용되어 전문성을 부여했습니다.
    * Cursor: IDE 내 페어 프로그래머처럼 type 에러나 import 문제 등 코드 작성 과정의 즉각적인 문제를 해결했습니다.
    * Codex: 코드 분석 및 비교에 강점을 보여, 특정 테스트 간의 차이점 분석 등에 활용되었습니다.

    AI 팀원들의 실제 업무 방식은 다음과 같습니다.

    * SDET Agent:
    * Page Object Model (POM) 도입: 테스트가 5개 정도로 늘어나 코드가 복잡해지자, SDET Agent는 selector의 중복과 유지보수 문제를 해결하기 위해 POM 도입을 제안했습니다. 그 결과, RefundApplicationPage와 같은 클래스 내에 selector를 캡슐화하고 async clickApplyButton(), async fillAccountNumber()와 같은 메서드를 정의하여 재사용성과 유지보수성을 극대화했습니다. 셀렉터 변경 시 단 한 곳만 수정하면 되게 하여 '중복 셀렉터 스트레스'를 해소했습니다.
    * 약관(동의) 플로우 자동 정리: 서비스별, 유입 경로별로 상이한 약관 구조(개수, 순서, 명칭) 문제를 해결하기 위해 AI에게 '서비스별 약관 구조 자동 감지 및 처리 유틸리티' 생성을 요청했습니다. Claude는 URL 기반 서비스 타입 감지, 체크박스 개수에 따른 신/구 유저 구분, 서비스별 필수 약관 목록 자동 매칭, "모두 동의하기" 버튼 부재 시 fallback 로직 등의 아이디어를 제안했으며, 이를 통해 하나의 clickInitialConsent() 함수만으로 모든 약관 변화에 자동으로 대응할 수 있게 되었습니다.
    * Documentation Specialist: "오늘 커밋 기반으로 일지 정리해줘"와 같은 간단한 요청만으로 '신규 테스트 추가', '월세 공제 로직 수정' 등 커밋 히스토리를 바탕으로 상세한 회고록을 자동으로 생성하여 문서화 부담을 줄였습니다.
    * Git Master: 초기 'fix'나 'update test'와 같은 간략한 커밋 메시지 대신, feat(test-15): prevent duplicate userNo across tests - ensure each test uses unique userNo와 같이 의미론적이고 구체적인 커밋 메시지를 생성하여 팀의 개발 발자취를 명확하게 기록했습니다.

    AI-사람-테스트 루프는 내부 메신저를 통해 유기적으로 연결되었습니다. 각 테스트가 끝날 때마다 결과, 실행 시간, 환경, UserNo, 관련 티켓 브랜치 등의 정보가 자동으로 메시지로 전달되었습니다. 테스트 실패 시에는 에러 메시지, 실패 단계, 관련 로그(EventID) 등이 추가되어 실패 원인 추적을 용이하게 했습니다. 특히, 실패 스레드에 테스트 리포트와 실패 지점 스크린샷이 첨부되어 즉각적인 논의가 가능했습니다. 이 시스템 덕분에 코드를 직접 치는 시간보다 AI와 내부 메신저로 대화하는 시간이 더 많아졌습니다.

    5개월간의 개발 여정은 다음과 같습니다.
    * 7월 (파일럿 시작): 핵심 테스트 5개 제작 및 Page Object Model 도입을 통한 테스트 유틸 함수 틀 완성.
    * 8월 (문서화 & React 타이밍 이슈 해결): React UI의 특성상 '보인다(Visible)'와 '클릭 가능(Interactable)' 시점이 다른 문제(DOM 렌더링 후 onClick 이벤트 핸들러 바인딩 지연)를 해결했습니다. Claude는 이 문제를 "Playwright가 클릭을 시도할 때 이벤트 핸들러가 아직 바인딩되지 않은 상태"로 정확히 진단하고, 다음과 같은 Interaction Readiness 전략을 제안했습니다.
    * waitForReactInteractionReady() 함수를 통해 DOMContentLoaded, visible 상태 확인은 물론, React hydrationeffect 바인딩까지 고려하여 typeofel.onclick===functiontypeof el.onclick === 'function'과 같이 이벤트 핸들러 바인딩 여부를 명시적으로 확인하는 방법을 적용했습니다.
    * safeClick() 함수를 통해 표준 클릭, 네이티브 키보드 인터랙션(Enter), JS 디스패치(el.click())의 순서로 안정적인 fallback 전략을 구현했습니다.
    * 최종적으로 clickReactButton() 함수를 통해 waitForReactInteractionReady()safeClick()을 결합하여 클릭 성공률을 70%에서 100%로 끌어올렸습니다.
    * 9월 (대규모 리팩토링 & 테스트 격리): 2,147줄의 파일을 3개로 분리하고, 23개 테스트의 import를 자동 수정했으며, userNo 충돌 문제를 해결하여 자동화 품질 관리 단계로 진입했습니다.
    * 10월 (약관 시스템 재설계): 복잡해진 약관 관리를 위해 AI는 consentOptions.ts로 모든 약관을 중앙 관리하고, URL 기반 서비스 타입 자동 감지 및 동의 내역을 이모지로 표시하는 내부 메신저 알림을 제안했습니다. 이를 통해 3일 만에 약관 정합성 확인 시스템이 구축되었고, 이후 약관 추가는 설정 파일 한 줄 수정으로 가능해졌습니다.
    * 11월 (35개 테스트 완성 & 운영 모드 진입): 탈퇴, 홈택스 가입 등 추가 테스트를 포함하여 35개 테스트를 완성하고, 안정적인 운영 단계에 도달했습니다.

    5개월간의 실험 결과, 저자는 문제 정의, 요구사항 정리, AI에게 맥락과 제약 설명, 결과물 검토 및 승인에 대부분의 시간을 할애했으며, 코드를 직접 작성하는 시간은 10% 미만이었습니다. 저자는 AI가 QA를 대체하는 것이 아니라 QA의 역량을 증폭시키는 역할을 하며, "AI가 좋은 품질의 속도를 만든다면, QA는 그 속도가 향해야 할 '방향'을 만드는 사람이다"라는 인사이트를 얻었습니다.

    원본 보기
    Service
    Shared by Anonymous