
요약

안녕하세요! 당근 모바일실에서 Test Automation Engineer로 일하고 있는 Lily예요.
모바일실은 여러 팀이 당근 앱을 더 빠르고 안정적으로 만들 수 있게 그 바탕이 되는 플랫폼을 만드는 곳이에요. 그 안에서 저는 테스트 자동화를 맡고 있어요. 실제 기기에서 테스트를 실행할 수 있는 기반을 만들고, 매일 안정적으로 돌아가도록 다듬고 있어요. 각 팀이 직접 품질을 확인할 수 있게 하는 게 목표예요.
이 글에서는 QAHub를 만들면서 풀었던 문제들을 이야기해보려고 해요. 한 문장으로 시작한 요청이 실제 기기에서 돌아가는 테스트가 되기까지의 과정이에요.
한눈에 보는 QAHub
QAHub는 테스트를 만들고, 관리하고, 실행하는 전 과정을 담고 있어요.
처음에는 흩어진 테스트 기록을 한곳에 모으는 것부터 시작했어요. 그다음에는 QA가 아니어도 테스트를 실행할 수 있게 만들었고요. 지금은 AI가 테스트를 만들고 실행하는 데까지 확장하고 있어요.

한 문장에서 실제 기기 실행까지

QAHub에서는 이 한 문장으로 테스트를 시작할 수 있어요.
사용자가 한 문장을 입력하면 AI가 먼저 테스트 Flow를 만들어요. 그다음 실제 기기에서 앱을 직접 조작해 테스트해요.
당근은 목적조직마다 QA를 따로 두지 않고, 각 팀이 직접 테스트하고 배포해요. 그래서 AI Tests는 누구나 쉽게 테스트를 만들고 실행할 수 있게 하는 데 초점을 맞췄어요.


Flow 안에는 코드 스텝과 AI 스텝이 함께 들어갈 수 있어요. 로그인이나 딥링크처럼 이미 정해진 동작은 코드로 실행하고, 화면을 보고 판단해야 하는 일은 AI가 맡아요. 탭, 입력 같은 기본 동작부터 이미지 매칭, 푸시 알림 열기, 로그 이벤트 검증까지, 스텝을 직접 골라 Flow를 만들 수도 있어요. 채팅처럼 상대가 있어야 하는 기능은 기기 두 대로 테스트해요.
만든 Flow는 저장해 다시 실행할 수 있고, 반복 검증이 필요하면 정식 리그레션 테스트로 편입해요.
물론 처음부터 한 문장만 입력하면 테스트가 돌아갔던 건 아니에요. 흩어진 테스트 기록과 케이스를 한곳에 모으고, 실제 기기를 제어하고, AI가 테스트를 끝까지 수행할 수 있는 실행 환경을 갖춰야 했죠.
이제 이 과제들을 어떻게 풀었는지, QAHub의 테스트 기록과 자동화 기반, AI 실행 구조를 차례로 소개해볼게요.

테스트 데이터의 중앙화
처음부터 AI 테스트를 만들 생각은 아니었어요. 가장 먼저 한 일은 여기저기 흩어져 있던 테스트 기록을 한곳에 모으는 것이었어요. 외부 툴, 노션, 구글 시트에 따로 있던 것들이요. 지금은 22개 프로젝트, 2,000개 이상의 테스트케이스가 이 위에서 관리되고 있어요.
기록을 한곳에 모은 다음에는 테스트를 만드는 과정에도 AI를 활용하기 시작했어요. 같은 기능을 테스트해도 작성자마다 적는 방식이 달랐어요. 어떤 케이스는 아주 자세했고, 어떤 케이스는 한두 줄뿐이었죠. 읽고 관리하는 데 시간이 꽤 들었어요.
그래서 만든 것이 Test Copilot이에요. 기획 문서와 GitHub 코드를 분석하고, 사람이 분석 결과를 검수하면 테스트 설계·테스트케이스·BDD 시나리오를 생성해요. 형식은 자연스럽게 통일되고, 놓치기 쉬운 테스트 범위도 함께 확인할 수 있게 됐어요.
이걸 만들면서 테스트케이스를 어떻게 써야 하는지도 다시 보게 됐어요. AI가 클릭 순서를 만들고 실행까지 할 수 있다면, 사람이 더 명확히 적어야 할 건 “어떤 순서로 누르는가(How)”보다 “무엇이 지켜져야 하는가(What)”라고 생각해요.
지금은 클릭 순서를 나열하기보다, 제품과 기능이 반드시 보장해야 할 것을 테스트 명세에 적고 있어요.
자동화 실행 환경의 표준화
QAHub 이전에도 코드 기반 자동화 테스트는 있었어요. 자동화 테스트가 있다고 해서 누구나 바로 실행할 수 있는 건 아니었어요. 어떤 저장소를 열어야 하는지, 어떤 스크립트를 골라야 하는지, 어떤 빌드와 기기를 써야 하는지 아는 사람만 실행할 수 있었어요.
그래서 QAHub에서 누구나 테스트를 돌릴 수 있게 만들었어요. 저장소나 스크립트를 몰라도, 버튼 몇 번이면 돼요. 시나리오를 고르고 플랫폼(Android·iOS·Web), 빌드 타입, 로케일(KR·JP·CA·US)을 선택하면 실제 기기에서 테스트가 실행돼요.
결과는 테스트케이스 단위로 QAHub에 쌓이고, 실패한 케이스에는 스텝별 스크린샷과 레코딩 영상이 함께 남아요.
이 테스트들은 매일 아침 최신 빌드에서 자동으로 실행되고, 필요할 때는 버튼 하나로 다시 실행할 수 있어요.
Self-healing 기반 실행 안정화
갑자기 뜨는 팝업이나 바뀐 Selector 때문에 테스트가 멈추면, 제품에 문제가 있는지 확인하기 어려워요. Selector는 화면에서 버튼 같은 요소를 찾는 주소예요. 앱 코드가 바뀌면 이 주소도 달라질 수 있어요.
팝업이 생길 때마다 코드를 추가하고, Selector가 바뀔 때마다 수정하기엔 손이 너무 많이 가요. 팝업은 계속 새로 생기고 나라마다 문구도 다르니까요. 매번 사람이 고치지 않아도 테스트를 이어갈 수 있게, 처음부터 Self-healing을 넣었어요.
복구는 막힌 이유에 따라 세 가지로 나뉘어요.

Selector Healing은 버튼 이름이 바뀌거나, 겉모습은 그대로여도 앱 코드가 달라져 기존 Selector로 요소를 찾지 못할 때 동작해요.

직전 스텝도 함께 보내요. “방금 글쓰기 화면에 들어왔다”는 걸 알면 AI가 찾아야 할 요소를 더 정확히 짚을 수 있거든요.
화면에 보이는 글자로 찾기 때문에 언어가 달라도 괜찮아요. 코드에는 ‘제목’이라고 적혀 있어도 일본어 화면에서는 ‘タイトル’를 찾아요.
복구에 성공하면 “실패한 Selector → 추천 Selector”가 슬랙으로 와요. 테스트는 먼저 실행을 이어가고, 나중에 사람이 추천된 Selector를 코드에 반영할 수 있어요.
Popup Healing은 동작할 때마다 화면을 다시 확인해요. 동네 인증처럼 테스트가 거쳐야 하는 화면은 닫지 않고 진행해요.

실제 사례를 하나 볼게요. ‘나의 당근’ 탭을 열려는데 시스템 권한 창이 화면을 가리고 있었어요. AI가 ‘허용’을 눌러 창을 넘기고, 화면에 보이는 ‘나의 당근’ 글자로 탭을 다시 찾아 테스트를 끝까지 통과시켰어요.

복구했다고 그냥 통과시키지는 않아요. AI가 버튼을 대신 눌렀다면 다음 화면이 기대와 맞는지 다시 확인하고, 다르면 실패로 기록해요. 스텝마다 Self-healing을 쓸지 말지도 코드에서 정할 수 있어요.
테스트는 한 달에 3,000건 넘게 실행돼요. 8월에는 실행 중 복구가 필요했던 테스트 가운데 90% 넘게는 사람의 개입 없이 끝까지 통과했어요.

여기까지 만들고 나니, 다음 고민은 코드만으로 자동화하기 어려웠던 영역까지 어떻게 가져올 것인가였어요.
코드 기반 자동화와 AI의 결합
기존에는 Appium과 Selenium으로 모바일 앱과 웹을 자동화해 왔어요. 정해진 동작을 반복하는 테스트는 코드로 빠르고 안정적으로 실행할 수 있었어요. 다만 화면을 보고 판단해야 하는 동작은 구현과 유지보수에 드는 비용이 커서 자동화하기 어려웠어요.
화면을 보고 판단해야 하는 동작은 AI에게 맡겨보기로 했어요. Self-healing에서는 AI가 막힌 순간에만 개입했다면, 이번에는 테스트 동작 자체를 맡겼어요. AI가 화면을 해석하고 다음 동작을 스스로 결정하도록 한 거예요.
전체를 맡겨보니 실행 시간이 길어지고 비용도 늘었어요. 같은 테스트에서도 버튼을 찾지 못해 멈추는 등 결과가 일정하지 않았고요.
반복해서 실행하려면 실행 시간을 줄이고 결과도 일정하게 만들어야 했어요. 그래서 로그인이나 화면 이동처럼 이미 빠르고 안정적으로 자동화된 동작은 코드 스텝으로 실행하고, 화면을 보고 판단하거나 탐색해야 하는 부분만 AI 스텝으로 실행하기로 했어요.
문제는 AI 스텝을 반복할 때였어요. 매번 같은 판단을 다시 시키면 실행 시간과 비용이 늘고, 결과도 일정하지 않았어요. 한 번 성공한 경로를 다음 실행에서 다시 쓸 수 있게 만들었어요.
Path Replay 기반 AI 실행 경로 재사용
AI가 한번 성공한 길을 다음에도 쓰기로 했어요. 어떤 화면에서 무엇을 눌렀는지, 그때 화면이 어떻게 생겼는지를 함께 저장해요. 다음 실행에서 이 경로를 그대로 재생하는 기능이 Path Replay예요. 개별 글자나 사진보다 화면의 전체적인 구조를 기억해서, 게시글 내용이나 닉네임이 달라져도 배치가 같으면 같은 화면으로 인식할 수 있어요. 화면 스크린샷을 64비트 지문으로 줄여 비교하고, 다른 비트가 10개 이하면 같은 화면으로 봐요.
다음 실행에서 같은 화면을 만나면, AI를 다시 호출하는 대신 저장한 경로를 그대로 재생해요. 이때는 AI 호출 비용 없이 더 빠르게, 매번 같은 방식으로 움직여요.
화면이 달라졌다면 저장된 경로를 쓰지 않고, AI가 다시 길을 찾아요.

비슷하게 생긴 화면을 잘못 인식하는 경우를 막는 안전장치도 있어요. 기억한 동작을 실행하기 전에 실제로 대상 요소가 예상한 위치에 있는지 다시 확인해요. 맞지 않으면 기존 경로를 사용하지 않고 AI에게 판단을 넘겨요.
성공한 스텝만 저장해요. 잘못 학습된 경로는 사람이 직접 지울 수 있게 했고요. 로케일이 바뀌면 화면 지문도 달라지기 때문에, 경로는 로케일별로 따로 쌓여요.
8월 기준 리그레션에 등록된 AI 스텝 80개 중 35개(44%)가 이미 실행 경로를 기억하고 있어요. 이 35개 스텝은 AI 호출 없이 수 초 안에 재생되고, 나머지 45개에서만 AI를 호출해요.
효과는 같은 시나리오를 반복해서 돌릴 때 가장 잘 보여요. 시나리오 하나를 예로 들어 볼게요.

실행을 반복할수록 기억한 경로가 늘어나면서, AI 호출은 5분의 1 수준으로, 실행 시간은 3분의 1 수준으로 줄었어요.
코드로 만들고 유지하기 어려워 자동화를 미뤄두었던 화면들도, 이 방식으로 하나씩 자동화하고 있어요.
테스트가 지나간 화면도 모으고 있어요. 이렇게 앱 전체의 화면 카탈로그를 만들어요. 카탈로그에 없는 화면을 만나면 진입 경로와 함께 새 화면 후보로 제안하고, 실제 등록 여부는 사람이 판단해요.
페르소나 기반 사용성 검증
AI Tests에는 페르소나를 붙일 수도 있어요.
페르소나는 나이와 상황, 당근을 사용하는 목적을 설정한 가상의 사용자예요. AI는 그 설정에 맞춰 앱을 사용하면서 문구를 이해할 수 있는지, 다음 행동을 찾기 쉬운지 같은 점도 살펴봐요.
예를 들어 “이 유저가 이 문구를 이해할 수 있을까?”, “다음에 무엇을 해야 할지 바로 알 수 있을까?” 같은 것들이에요.
이런 관찰이 테스트의 성공/실패를 결정하지는 않아요. 별도의 참고 리포트로 남기고, 최종 판단은 사람이 해요.
기능이 동작하는지 확인하는 데 더해, 페르소나로는 사용 중 헷갈릴 만한 문구나 화면도 살펴볼 수 있어요.
실패 분석과 디버깅 자동화
자동화를 운영해보면 실행 자체보다 실패 원인을 찾는 데 가장 많은 시간이 들어요. “실패했다”는 결과만 남으면 사람이 다시 화면과 로그를 뒤져야 하거든요.
그래서 QAHub의 결과 화면은 실패 원인을 빠르게 찾기 위한 디버깅 도구로 만들었어요.
- 스텝별 스크린샷 리플레이: 실행 과정을 장면 단위로 되짚어보며 어디서부터 예상과 달라졌는지 확인해요.
- 실패 영상: 실패 직전부터 종료까지 필요한 구간만 잘라 자동으로 첨부해요.
- 스텝별 AI 판단 기록: AI가 무엇을 보고 왜 그 행동을 선택했는지 남겨요.
- AI 실패 분석: 무엇을 하려다 어디서, 왜 막혔는지와 문제의 성격이 무엇인지 짧게 정리해요.

AI 서버가 잠시 응답하지 않아 멈춘 테스트가 있었어요. 분석 AI는 원인을 “탭 상태 인식이 지연됐다”고 설명했어요. 그럴듯했지만 실제 원인과 달랐어요.
이런 오진을 줄이려고 분석 AI에게는 스텝별 판단 기록과 실제 에러만 근거로 줬어요. 기록에 없는 내용은 추정하지 않도록 했어요.
실패 원인을 설명할 때는 실제로 남은 기록 안에서 말해야 한다고 생각했어요. 그럴듯한 오진을 따라가면 원인을 찾는 데 오히려 더 오래 걸릴 수 있으니까요.
마치며
한 문장으로 앱을 테스트한다는 건, 한 문장만으로 되는 일이 아니었어요. 흩어진 기록을 모으고, 누구나 실행할 수 있는 환경을 만들고, 실행 중 막힌 테스트가 다시 이어질 수 있게 한 뒤에야 AI가 그 위에서 움직일 수 있었어요.
그 과정에서 몇 가지 원칙이 분명해졌어요.
- 데이터를 먼저 모을 것. 흩어져 있던 기록이 한곳에 쌓이자 테스트 생성부터 실패 분석까지 같은 데이터를 활용할 수 있었어요.
- AI를 어디에 쓸지보다 어디에 쓰지 않을지를 정할 것. 정해진 동작은 코드로 빠르고 안정적으로 실행하고, 화면을 보고 판단해야 하는 부분에만 AI를 활용했어요.
- 실패를 다음 실행에 반영할 것. AI가 불안정하게 움직이거나 실패 원인을 잘못 설명할 때마다, 같은 문제가 반복되지 않도록 규칙과 안전장치를 보탰어요.
그렇게 쌓인 건 실행 결과만이 아니에요. 저장한 Flow는 리그레션 자산이 되고, AI가 찾은 경로는 다음 실행의 기억이 되고, 거쳐 간 화면은 앱의 지도가 돼요. 테스트를 돌릴수록 다음 테스트가 쉬워지는 구조예요.
앞으로는 한 문장으로 시작한 테스트가 자연스럽게 리그레션 자산으로 이어지는 구조를 더 단단하게 만들어가려고 해요. 다음 글에서는 이 방식이 실제 테스트를 어떻게 바꿨는지, 더 많은 숫자로 이야기해볼게요.
당근 모바일실에서는 이런 문제를 함께 풀어 갈 동료를 찾고 있어요. 테스트 자동화와 AI로 여러 팀이 스스로 품질을 확인할 수 있게 돕는 일에 관심이 있다면, 당근 채용 공고를 확인해 주세요.
한 문장으로 앱을 테스트하기까지 was originally published in 당근 기술 블로그 on Medium, where people are continuing the conversation by highlighting and responding to this story.