본문으로 건너뛰기
중급약 28분

TestRail 실전: 스위트·런·마일스톤으로 테스트를 굴리기

케이스를 쓰는 곳과 실행하는 곳이 분리된 구조를 이해하면 TestRail이 한 번에 잡힌다. 프로젝트 모드 선택부터 조합 실행, 자동화 결과 연동까지 다룬다.

  • #TestRail
  • #테스트관리도구
  • #테스트런
  • #마일스톤
  • #trcli

개념

하나만 이해하면 되는 것 — 케이스와 실행은 다른 곳에 산다

TestRail을 처음 열면 메뉴가 많아 막막하다. 그런데 이 도구의 구조는 문장 하나로 요약된다.

케이스를 쓰는 곳(Test Cases)과 실행하는 곳(Test Runs)이 분리돼 있다.

모듈 7(레슨 1)에서 "반복 실행 이력이 만드는 가치"를 배웠다. 같은 케이스를 여러 번 실행하고 그 결과를 비교할 수 있어야 한다는 것. TestRail은 그 요구를 구조로 못 박아둔 도구 다.

프로젝트(Project)
 └─ 테스트 스위트(Suite)          ← 케이스가 사는 저장소
     └─ 섹션(Section) / 하위 섹션
         └─ 케이스(Case)          ← 여기서는 실행하지 않는다. 정의만 있다
                 │
                 │  실행할 때 케이스를 "선택해서" 런에 담는다
                 ▼
프로젝트
 └─ 마일스톤(Milestone)           ← 릴리즈 단위 묶음
     └─ 테스트 플랜(Plan)          ← 여러 런의 묶음 + 구성 조합
         └─ 테스트 런(Run)         ← 한 번의 실행 회차
             └─ 테스트(Test)       ← 런에 담긴 케이스의 "그때 그 인스턴스"
                 └─ 결과(Result)   ← Passed / Failed / Blocked …

이 그림을 이해하면 초보자가 가장 자주 하는 질문들이 한 번에 풀린다.

  • "케이스를 고쳤는데 지난 런의 내용이 안 바뀌어요" → 당연하다. 런에 담긴 테스트는 그때의 스냅샷 이다. 과거 실행 이력이 나중 수정으로 훼손되면 이력의 의미가 없다.
  • "같은 케이스를 두 번 실행하고 싶어요" → 런을 두 개 만든다. 케이스는 하나, 실행은 여럿이다.
  • "이번 릴리즈 결과만 모아 보고 싶어요" → 마일스톤으로 묶는다.

프로젝트 모드 — 처음에 정하고 되돌리기 어려운 선택

프로젝트를 만들 때 스위트 모드 를 고른다. 세 가지다.

모드구조적합한 상황
단일 저장소케이스 전체가 하나의 저장소에, 섹션으로만 구분대부분의 팀. 단순하고 관리가 쉽다
단일 저장소 + 베이스라인저장소를 분기(branch)해 버전별 케이스를 병행 관리여러 제품 버전을 동시에 유지보수
다중 테스트 스위트스위트를 여러 개 만들어 완전히 분리한 프로젝트 안에 성격이 크게 다른 영역이 공존

실무 조언은 명확하다 — 특별한 이유가 없으면 단일 저장소로 시작한다.

이유가 둘이다. 첫째, 다중 스위트는 관리 비용이 눈에 띄게 늘고 대부분의 팀에게 그만한 이득이 없다. 섹션으로 나누면 충분하다. 둘째, 모드 변경에는 제약이 있다. 특히 다중 스위트로 갔다가 단일 저장소로 되돌리는 것은 사실상 어렵다. 시작 시점의 선택이 오래 간다는 뜻이다.

베이스라인은 "v1.x는 유지보수하면서 v2.x를 개발한다"처럼 케이스 자체가 버전별로 갈라지는 상황에서만 값을 한다. 그런 상황이 아니라면 복잡도만 늘어난다.

케이스 작성 — 템플릿과 References

케이스를 만들 때 템플릿 을 고른다.

템플릿구조언제
Test Case (Text)전제조건 + 절차 + 기대결과를 자유 서술짧고 단순한 케이스
Test Case (Steps)단계별로 행위와 기대결과를 행으로 분리결과를 단계별로 기록해야 할 때
Exploratory Session미션(Charter)과 목표 중심모듈 5의 탐색적 테스팅 세션

Steps 템플릿의 장점은 실행 중에 어느 단계에서 실패했는지 를 기록할 수 있다는 점이다. 8단계짜리 케이스가 "Failed"라고만 남으면 나중에 아무도 어디서 깨졌는지 모른다.

References 필드가 QA에게 가장 중요한 칸이다. 여기에 요구사항이나 Jira 키(SHOP-241)를 적어두면, 케이스가 어떤 요구사항을 검증하는지가 데이터로 남는다. 모듈 2에서 배운 요구사항 추적성, 모듈 25에서 본 규제 도메인의 추적성 요구가 여기서 실체를 갖는다.

이 필드를 채워두면 나중에 Coverage for References 리포트 로 "이 요구사항을 검증하는 케이스가 있는가, 결과는 어땠는가"를 뽑을 수 있다. 안 채워두면 그 리포트는 영원히 비어 있다.

섹션 구조를 짜는 원칙 도 짚어두자. 흔한 실수는 화면 구조를 그대로 베끼는 것이다.

잘 안 되는 구조더 나은 구조
화면 이름 그대로(로그인 화면 / 마이페이지 화면 …)기능·흐름 단위(인증 / 주문 / 결제 / 알림)
개발 모듈 구조 그대로사용자 여정 단위

화면 기준으로 짜면 화면이 개편될 때마다 케이스 트리를 다시 짜야 하고, 한 기능이 여러 화면에 걸치면 케이스가 흩어진다. 기능 단위가 화면보다 오래 산다.

런·플랜·구성 — TestRail이 강한 지점

여기가 다른 도구와 확실히 갈리는 부분이다.

무엇인가언제 쓰나
테스트 런(Run)케이스 묶음을 한 번 실행하는 회차회귀 1차, 스모크 등 단일 실행
테스트 플랜(Plan)여러 런을 하나로 묶은 것한 릴리즈에서 여러 스위트를 동시에 돌릴 때
구성(Configuration)환경 축(브라우저·OS·기기 등)같은 케이스를 환경별로 실행해야 할 때

구성이 핵심이다. 플랜에 구성을 붙이면 케이스 × 환경 조합만큼 런이 자동 생성 된다.

플랜: "v2.4.0 릴리즈 회귀"
 ├─ 런: 결제 스위트 × Chrome / Windows
 ├─ 런: 결제 스위트 × Safari / macOS
 ├─ 런: 결제 스위트 × Chrome / Android
 └─ 런: 알림 스위트 × Chrome / Windows

모듈 13(레슨 8)에서 배운 크로스 브라우저 전략이 도구에서 이렇게 구현된다. 조합을 손으로 만들면 관리가 무너지지만, 구성으로 만들면 "Safari에서만 실패하는 케이스" 를 리포트로 바로 뽑을 수 있다.

마일스톤 은 그 위의 묶음이다. 릴리즈 단위로 런·플랜을 모으고, 시작·종료일을 걸어 진행률을 본다. 하위 마일스톤으로 계층을 만들 수도 있다. 실무에서는 릴리즈 = 마일스톤 으로 놓는 것이 가장 단순하고 잘 돈다.

결과 상태 — Blocked를 제대로 쓰는 팀이 드물다

기본 상태는 다섯 개다.

상태의미실무에서 자주 틀리는 점
Passed기대대로 동작
Failed기대와 다름결함 등록 없이 Failed만 남기면 추적이 끊긴다
Blocked실행할 수 없었음이걸 Failed로 기록하는 팀이 많다
Retest다시 확인 필요수정 후 재검증 대기 표시로 유용
Untested아직 실행 안 함수동으로 지정할 수 없는 기본 상태다

Blocked와 Failed의 구분이 지표를 바꾼다. 로그인 서버가 죽어서 결제 케이스를 아예 못 돌렸다면 그건 Failed가 아니다. Failed로 기록하면 "결제 기능에 결함 20건"처럼 보이고, 실제로는 환경 문제 하나다. 모듈 6 (레슨 5)의 지표가 오염되는 전형적 경로다.

Failed를 기록할 때는 Defects 필드에 결함 키를 넣는다. Jira를 연동해 두면 이 칸에서 바로 이슈를 만들거나 링크할 수 있고, 그러면 케이스 → 실행 결과 → 결함 의 사슬이 완성된다. 이 사슬이 있어야 "이 결함은 어떤 테스트에서 나왔나", "이 요구사항의 검증 상태는 무엇인가"에 답할 수 있다.

필요하면 커스텀 상태를 추가할 수 있지만, 늘리기 전에 정말 필요한지 따져본다. 상태가 늘면 집계가 복잡해지고 사람마다 다르게 쓴다.

리포트 — 무엇을 언제 뽑는가

TestRail의 리포트는 종류가 많다. QA가 실제로 쓰는 것 위주로 정리한다.

리포트답하는 질문쓰는 시점
Summary이번 실행의 전체 통과율은?차수 종료 시
Comparison for Cases같은 케이스가 회차별로 어떻게 변했나회귀 추세 확인
Coverage for References이 요구사항은 검증됐나릴리즈 판단, 감사 대응
Defects이 실행에서 나온 결함은?결함 트리아지
Activity누가 언제 무엇을 했나진행 상황 점검

Comparison for Cases가 가장 저평가된 리포트다. 회차별로 같은 케이스의 결과를 나란히 보여주므로, 자꾸 깨지는 케이스 가 눈에 띈다. 모듈 13 (레슨 6)에서 배운 플래키 테스트를 수동 케이스 영역에서 찾아내는 방법이기도 하다. 매번 통과했다가 이번에만 실패한 것과, 세 번 중 두 번 실패하는 것은 전혀 다른 문제다.

자동화 결과 밀어넣기 — trcli

수동 케이스만 관리하는 TestRail은 절반만 쓰는 것이다. 자동화 결과를 같은 화면에 모으면 릴리즈 판단을 한 곳에서 할 수 있다.

공식 CLI 도구가 trcli 다. JUnit XML, Robot Framework, Cucumber 등 표준 리포트 형식을 읽어 TestRail에 런을 만들고 결과를 올린다.

pip install trcli

가장 기본적인 사용 형태다.

trcli -y \
  -h https://example.testrail.io \
  --project "SHOP" \
  -u "$TESTRAIL_USER" -k "$TESTRAIL_API_KEY" \
  parse_junit \
  -f "reports/junit-*.xml" \
  --title "CI 회귀 - build 482"

CI에 붙이면 모듈 14(레슨 2)에서 만든 워크플로의 마지막 단계가 된다.

# .github/workflows/test.yml 의 마지막 단계 예시
- name: TestRail에 결과 업로드
  if: always()          # 테스트가 실패해도 결과는 올린다
  run: |
    trcli -y -h "$TR_HOST" --project "SHOP" \
      -u "$TR_USER" -k "$TR_KEY" \
      parse_junit -f "reports/*.xml" \
      --title "CI ${{ github.ref_name }} #${{ github.run_number }}" \
      --milestone-id 42
  env:
    TR_HOST: ${{ secrets.TESTRAIL_HOST }}
    TR_USER: ${{ secrets.TESTRAIL_USER }}
    TR_KEY: ${{ secrets.TESTRAIL_API_KEY }}

if: always() 를 빠뜨리면 테스트가 실패했을 때 결과가 안 올라간다. 정작 가장 보고 싶은 회차의 데이터가 비는 셈이라, 이 한 줄이 중요하다.

자동화 결과와 기존 케이스를 잇는 방식(case matcher)도 알아둬야 한다. 테스트 이름에 케이스 ID를 넣거나, 프로퍼티로 매핑하거나, 자동 생성하게 할 수 있다. 매핑 규칙을 정하지 않으면 실행할 때마다 케이스가 새로 만들어져 저장소가 부풀어 오른다 — 실제로 자주 벌어지는 사고다.

안티패턴 — TestRail이 무너지는 전형적 경로

1) 케이스 폭발. "모든 것을 케이스로"라는 생각으로 만들다 보면 3,000개가 된다. 그리고 아무도 전부 실행하지 못한다. 모듈 11(레슨 4)의 자동화 부채와 같은 문제다. 실행되지 않는 케이스는 자산이 아니라 부채다.

2) 화면 구조를 그대로 베낀 섹션. 앞에서 다룬 그대로. 화면이 바뀌면 트리를 다시 짜야 한다.

3) 하나의 런을 계속 재사용. "이번에도 그 런에 다시 기록하죠"를 반복하면 이력이 사라진다. TestRail을 쓰는 이유 자체가 없어지는 실수다. 회차마다 새 런을 만든다.

4) Blocked를 Failed로 기록. 지표가 오염된다. 환경 문제와 제품 결함은 분리해야 한다.

5) Untested를 방치한 채 종료. 실행하지 않은 케이스가 절반인데 "통과율 100%"라고 보고하는 상황. 분모를 밝히지 않은 통과율은 거짓말에 가깝다. 종료 시 Untested 건수를 반드시 함께 보고한다.

6) 자동화 결과를 올리지 않음. 수동 결과만 TestRail에, 자동화 결과는 CI 로그에 있으면 릴리즈 판단을 두 화면에서 해야 한다. trcli로 합친다.

실무에서 왜 필요한가

TestRail은 국내외 QA 채용공고에서 가장 자주 언급되는 테스트 관리 도구다. "TestRail 사용 경험"이 요건에 적힌 공고를 만나면, 실제로 요구되는 것은 버튼 조작이 아니라 케이스 저장소와 실행 이력을 분리해 운영해본 감각 이다. 스위트를 어떻게 나눴고, 회차를 어떻게 관리했고, 자동화 결과를 어떻게 합쳤는지를 말할 수 있으면 그 경험은 다른 도구로도 그대로 옮겨간다.

조직 안에서의 실익도 크다. 릴리즈 판단 회의에서 "이번 회귀는 통과율 94%, 미실행 12건, 실패 8건 중 5건이 결제 영역이고 그중 2건은 Blocked 상태입니다"라고 말할 수 있는 근거가 화면에 있는 것과, 스프레드시트를 급히 정리해 가는 것은 다르다. 그리고 그 화면은 다음 회차에도 그대로 쓰인다.

무엇보다 요구사항 → 케이스 → 실행 → 결함 의 사슬이 데이터로 남는 것이 크다. 모듈 25에서 본 인증·감사 대응에서 요구되는 것이 정확히 이 사슬이고, 규제 도메인이 아니어도 "이 기능은 검증됐나"라는 질문에 즉답할 수 있다는 것은 QA의 기본 역량이다.

실습 과제

과제 1 — 섹션 구조 설계하기 (15분)

지금 다루는 제품의 테스트 케이스를 담을 섹션 트리를 설계한다. 2단계까지만 만들고, 각 섹션에 들어갈 케이스 수를 추정한다.

1단계 섹션2단계 섹션예상 케이스 수

작성 후 검증한다 — 화면 이름이 섹션 이름으로 들어간 곳이 있는가? 있다면 기능·흐름 이름으로 바꿔본다.

해설 보기

화면 이름을 피하라고 했지만, 예외가 하나 있다. 화면 자체가 기능인 경우 — 예를 들어 "대시보드"처럼 화면 하나가 독립된 기능 단위라면 그 이름을 써도 된다. 규칙의 목적은 이름을 금지하는 게 아니라 화면이 개편돼도 살아남는 구조 를 만드는 것이다.

예상 케이스 수를 적게 한 이유도 있다. 한 섹션에 200개가 몰린다면 그 섹션은 더 쪼개야 하고, 5개뿐인 섹션이 여럿이면 너무 잘게 나눈 것이다. 경험적으로 한 섹션에 20~60개 가 다루기 편한 범위다.

과제 2 — 조합 실행 계획 세우기 (20분)

다음 릴리즈의 회귀 테스트를 플랜으로 설계한다.

  1. 포함할 스위트(또는 섹션)를 정한다
  2. 구성 축을 정한다(브라우저·OS·기기 중 실제로 필요한 것만)
  3. 생성될 런의 개수를 계산한다
  4. 그 런을 전부 수행하는 데 걸릴 시간을 추정한다
  5. 시간이 부족하다면 무엇을 줄일 것인가 를 근거와 함께 적는다
해설 보기

5번이 이 과제의 핵심이다. 조합은 곱셈으로 늘어나기 때문에 금방 감당 불가능해진다. 3개 스위트 × 4개 브라우저 × 2개 OS면 이미 24개 런이다.

줄이는 방법은 모듈 3(레슨 5)에서 배운 조합 테스트 사고를 그대로 쓴다 — 모든 조합을 다 돌지 않고, 위험이 높은 조합에 집중 한다. 실무에서 흔히 쓰는 기준은 (1) 실사용 점유율이 높은 조합, (2) 과거에 환경별 결함이 나왔던 조합, (3) 렌더링 엔진이 다른 조합 하나씩.

그리고 줄인 결정을 기록으로 남기는 것 이 중요하다. "Safari/iOS 조합은 이번 회차에서 제외했고 그 이유는 이렇다"가 문서에 있으면, 나중에 그 조합에서 문제가 났을 때 논의가 "왜 안 했느냐"가 아니라 "기준을 조정하자"가 된다.

과제 3 — 상태 기록 규칙 정하기 (12분)

팀에서 쓸 결과 상태 규칙을 문서로 만든다. 아래 상황에 각각 어떤 상태를 기록할지 정하고 근거를 적는다.

  1. 기대와 다르게 동작한다
  2. 테스트 환경이 죽어서 실행 자체를 못 했다
  3. 선행 케이스가 실패해서 이 케이스를 진행할 수 없다
  4. 결함이 수정됐다고 해서 다시 확인해야 한다
  5. 시간이 부족해서 실행하지 못했다
  6. 동작은 하는데 명세가 애매해서 판단이 안 선다
해설 보기

1은 Failed, 2와 3은 Blocked, 4는 Retest, 5는 Untested(그대로 둔다).

6이 함정이다. 애매하다고 Passed로 넘기면 문제가 묻히고, Failed로 하면 개발자와 소모적인 논쟁이 된다. 실무에서 좋은 처리는 일단 Blocked 또는 Retest로 두고, 명세 확인 요청을 별도 이슈로 등록 하는 것이다. 모듈 2 (레슨 6)에서 배운 대로 — 애매한 요구사항은 테스트 결과가 아니라 요구사항 쪽에서 해결해야 할 문제 다.

이 규칙을 문서로 만들어두는 이유는 사람마다 다르게 기록하면 지표가 의미를 잃기 때문이다. 특히 여러 명이 같은 런에 결과를 기록할 때 차이가 크다.

과제 4 — 자동화 결과 연동 설계 (20분)

CI에서 TestRail로 결과를 올리는 파이프라인을 설계한다.

  • 어떤 리포트 형식이 나오는가(JUnit XML / Cucumber / Robot)
  • trcli 명령을 실제 값으로 작성한다
  • 자동화 케이스와 TestRail 케이스를 어떻게 매핑할 것인가
  • 런 제목 규칙(브랜치·빌드 번호를 포함하는가)
  • if: always() 를 넣어야 하는 이유를 한 줄로 적는다
  • 수동 결과와 자동화 결과를 같은 런에 담을 것인가 나눌 것인가, 그 이유

마지막 항목에 정답은 없다. 다만 결정하고 기록하는 것 이 중요하다.

자가 체크리스트

  • 케이스 저장소와 테스트 런이 분리된 구조를 그림으로 설명할 수 있다
  • 케이스를 수정해도 지난 런의 내용이 바뀌지 않는 이유를 설명할 수 있다
  • 스위트 모드 세 가지를 구분하고, 왜 단일 저장소로 시작하라고 하는지 말할 수 있다
  • 케이스 템플릿 세 종류의 차이와 Steps 템플릿의 이점을 설명할 수 있다
  • References 필드가 요구사항 추적성과 어떻게 연결되는지 말할 수 있다
  • 섹션을 화면 기준이 아니라 기능·흐름 기준으로 짜야 하는 이유를 설명할 수 있다
  • 런·플랜·구성의 관계를 설명하고, 조합 실행이 왜 유용한지 말할 수 있다
  • 마일스톤이 릴리즈 관리에서 하는 역할을 설명할 수 있다
  • Blocked와 Failed의 차이가 지표에 미치는 영향을 설명할 수 있다
  • Comparison for Cases 리포트로 무엇을 발견할 수 있는지 말할 수 있다
  • trcli로 CI의 자동화 결과를 TestRail에 올리는 흐름을 설명할 수 있다
  • if: always() 가 왜 필요한지, 케이스 매핑 규칙이 없으면 무슨 일이 생기는지 안다
  • TestRail이 무너지는 안티패턴 여섯 가지를 들 수 있다

흔한 실수

  • 하나의 런을 계속 재사용한다. 이력이 사라진다. 회차마다 새 런을 만든다.
  • Blocked를 Failed로 기록한다. 환경 문제가 제품 결함으로 집계돼 지표가 오염된다.
  • Untested를 밝히지 않고 통과율만 보고한다. 분모를 숨긴 통과율은 신뢰를 잃는 가장 빠른 길이다.
  • 섹션을 화면 구조로 짠다. 화면 개편마다 트리를 다시 짜야 하고, 한 기능의 케이스가 흩어진다.
  • References를 비워둔다. 요구사항 커버리지 리포트가 영원히 비어 있게 된다.
  • 다중 스위트 모드로 성급하게 시작한다. 관리 비용이 늘고, 단일 저장소로 되돌리기 어렵다.
  • 자동화 결과를 CI 로그에만 남긴다. 릴리즈 판단을 두 화면에서 하게 된다.
  • 케이스 매핑 규칙 없이 trcli를 돌린다. 실행할 때마다 케이스가 새로 생성돼 저장소가 부푼다.
  • CI 업로드 단계에 if: always() 를 빠뜨린다. 실패한 회차의 결과가 통째로 비어버린다.
  • 모든 것을 케이스로 만든다. 실행되지 않는 케이스는 자산이 아니라 부채다.

참고 자료

낯선 말 풀이

이 레슨에 나온 약어입니다. 본문에서도 처음 나올 때 점선으로 표시해 두었습니다 (제목과 링크 글자는 그대로 둡니다).

QA — 품질보증
만든 것이 쓸 만한지 확인하고, 애초에 덜 망가지게 만드는 방법을 정하는 일. "테스트"는 그 일의 일부다.
OS — 운영체제
기기를 돌리는 바탕 프로그램 — 윈도우, 맥, 안드로이드 같은 것.
CLI — 명령 줄 인터페이스
검은 화면에 글자로 명령을 적어 넣는 방식. 버튼은 없고 줄마다 명령을 쓴다.
JUnit — 제이유닛
자바로 만든 프로그램의 단위 시험을 쓰고 돌리는 가장 널리 쓰이는 도구.
XML — 확장 표시 언어
제이슨과 목적이 같은, 더 오래된 글자 형식. 꺾쇠 괄호로 이름을 감싼다.
CI — 지속적 통합
코드를 올릴 때마다 자동으로 합쳐서 빌드하고 시험까지 돌리는 방식.
ID — 식별자
무엇 하나를 다른 것과 구별하기 위해 붙인 이름이나 번호.
CI/CD — 통합·배포 자동화
합치고 시험하고 배포하는 과정을 자동으로 이어 둔 흐름 전체.
API — 응용 프로그램 인터페이스
프로그램끼리 주고받는 창구. 사람이 화면 버튼을 누르는 대신, 프로그램이 정해진 주소로 요청을 보내 답을 받는다.

용어집 전체 보기