테스트 케이스란? 작성 방법과 실제 예시 완전 가이드

테스트 케이스란 소프트웨어가 올바르게 동작하는지 확인하기 위한 「검증 절차서」입니다. 본 글에서는 테스트 케이스의 작성 방법·구성 요소·실무에서 활용할 수 있는 설계 노하우를 실제 예시와 함께 설명합니다. 「무엇을 써야 할지 모르겠다」「정상 케이스밖에 떠오르지 않는다」「사람마다 내용이 달라진다」는 고민을 갖고 계신 분께도 도움이 될 내용입니다.

「감으로 테스트하기」와 테스트 케이스에 기반한 설계 테스트는 버그 발견율과 팀 내 재현성 면에서 큰 차이가 납니다. 테스트 케이스 작성법을 익히는 것이 품질 보증의 출발점입니다.

📌 이런 분께 추천합니다

  • 테스트 케이스 작성법을 기초부터 배우고 싶은 QA 엔지니어·개발자
  • 「무엇을 어디까지 써야 할지」 고민 중인 분
  • 테스트 케이스가 개인 의존적이 되어 팀에서 공유하기 어려운 분
  • 자동화 테스트(pytest)에 테스트 케이스 설계를 활용하고 싶은 분

✅ 이 글을 읽으면 얻을 수 있는 것

  • 테스트 케이스의 구성 요소와 기본 작성법을 이해할 수 있다
  • 좋은 테스트 케이스와 나쁜 테스트 케이스의 차이를 구체적인 예시로 파악할 수 있다
  • 정상·비정상·경계값 분류 방법과 실무 활용법을 익힐 수 있다

👤 이 글을 쓴 사람

QA 엔지니어·테스트 자동화 엔지니어로 15년 이상의 실무 경험을 가진 Yoshi가 작성했습니다. 테스트 케이스 설계는 웹·임베디드·금융 등 다양한 도메인에서 실무로 다뤄온 주제입니다.

📌 결론

  • 테스트 케이스란 「사전 조건·실행 단계·예상 결과」를 하나의 세트로 정리한 검증 단위
  • 좋은 테스트 케이스는 「누가 실행해도 동일한 결과를 얻을 수 있는」 재현성이 핵심
  • 정상·비정상·경계값 3가지 분류를 의식해 작성하면 커버리지가 높아진다

테스트를 진행할 때 「어디서부터 시작해야 할지 모르겠다」 「테스트 내용이 사람마다 다르다」 「같은 버그를 반복해서 놓친다」는 문제는 많은 현장에서 발생합니다.

이러한 문제의 근본 원인 중 하나가 테스트 케이스 설계가 모호하다는 것입니다. 테스트 케이스를 올바르게 작성할 수 있게 되면 버그 누락이 줄고 팀 내 리뷰도 수월해집니다.

테스트 케이스란? 정의와 역할

테스트 케이스란 「특정 조건에서 소프트웨어의 동작을 검증하기 위한 절차와 예상 결과를 정의한 문서」입니다.

쉽게 말하면, 다음 네 가지 질문에 답하는 세트입니다.

질문테스트 케이스 상의 표현
무엇을 확인하는가?테스트 대상·테스트 명
어떤 상태에서 시작하는가?사전 조건
어떤 조작을 수행하는가?실행 단계
어떤 결과가 나오면 합격인가?예상 결과

테스트 케이스가 있으면 다음과 같은 효과를 기대할 수 있습니다.

  • 누가 실행해도 동일한 내용을 테스트할 수 있다 (재현성)
  • 무엇을 테스트했고 하지 않았는지 명확해진다 (추적성)
  • 버그가 재발했을 때 어떤 테스트가 누락됐는지 파악하기 쉽다
  • 새 팀원이 합류해도 즉시 테스트를 인수인계받을 수 있다
💡 테스트 케이스 vs 테스트 시나리오:자주 혼동되지만, 테스트 시나리오는 「사용자 유스케이스(사용 흐름)」를 기술한 것이고, 테스트 케이스는 그 안의 「단일 확인 포인트」입니다. 테스트 시나리오 하나에 여러 테스트 케이스가 대응하는 이미지입니다.

테스트 케이스의 구성 요소

테스트 케이스에 포함하는 항목은 프로젝트나 툴에 따라 다릅니다. 아래가 기본 구성입니다.

항목내용기입 예시
테스트 ID고유 식별 IDTC-LOGIN-001
테스트 명무엇을 확인하는지 한 문장으로정상_유효한 인증 정보로 로그인할 수 있는지
사전 조건테스트 시작 시의 상태테스트 사용자(test@example.com)가 등록되어 있을 것
실행 단계번호로 정리한 단계별 조작①이메일 입력 ②비밀번호 입력 ③로그인 버튼 클릭
예상 결과조작 후 발생해야 할 동작대시보드 화면(/dashboard)으로 이동한다
우선순위테스트 실행 우선순위높음 / 중간 / 낮음

규모가 큰 프로젝트에서는 아래 항목이 추가되기도 합니다.

추가 항목 (선택)용도
입력 데이터파라미터가 여러 개일 경우 별도 열로 관리
테스트 타입기능 테스트 / 회귀 테스트 / 탐색적 테스트 등 분류
추적성대응하는 요구사항 ID·티켓 번호 연결 (예:REQ-042)
실행 결과 / 실행일Pass / Fail 기록과 실시일

테스트 케이스 관리 툴 비교표

툴 선택은 팀 규모와 운용 방식에 따라 달라집니다.

툴소규모 팀대규모 팀특징
Excel / Google Sheets◎△초기 비용 없음·자유도 높음. 규모가 커지면 관리가 복잡해지기 쉽다
TestRail○◎실행·리포트·Jira 연동 기능이 충실. 팀과 프로젝트에 걸친 관리에 적합
Notion / Confluence◎○문서와 일원화 관리 가능. 테스트 전용 기능은 제한적

테스트 케이스 작성 순서

아래 순서를 따르면 누락이나 중복을 방지하기 쉬워집니다.

① 명세 확인
↓
② 테스트 관점 추출
↓
③ 정상·비정상·경계값으로 분류
↓
④ 테스트 케이스 작성
↓
⑤ 리뷰
↓
⑥ 실행·기록·업데이트

단계 1 — 명세 확인

먼저 명세서·요구사항 정의서·수락 조건(AC)을 읽습니다. 「어떤 입력에 대해 무엇이 일어나야 하는가」의 조건을 정리하는 것이 출발점입니다. 명세가 모호한 부분은 테스트 케이스를 작성하기 전에 개발자나 PO에게 확인해 두면 재작업을 줄일 수 있습니다.

단계 2 — 테스트 관점 추출

명세에서 테스트할 패턴을 「정상·비정상·경계값」 3가지로 분류합니다(자세한 내용은 후술). 이 분류가 있으면 테스트 케이스의 누락을 발견하기 쉬워집니다.

단계 3 — 테스트 케이스 작성

분류한 패턴마다 「사전 조건·실행 단계·예상 결과」를 구체적으로 기술합니다. 이때 테스트 케이스 1개 = 확인 포인트 1개의 원칙을 지키는 것이 중요합니다. 여러 확인을 하나로 묶으면 어디서 실패했는지 특정하기 어려워집니다.

단계 4 — 리뷰

작성한 테스트 케이스는 자기 점검만이 아니라 다른 사람에게 리뷰받으면 누락을 발견하기 쉬워집니다. 「이 단계로 실제로 재현할 수 있는가」 「예상 결과는 구체적인가」 2가지를 중심으로 확인받아 보세요.

단계 5 — 실행·기록·업데이트

테스트 케이스는 만들고 끝이 아닙니다. 실행 결과(Pass/Fail)를 기록하고 명세 변경이 있으면 업데이트합니다. 오래된 테스트 케이스는 「테스트한 기분」만 줄 뿐, 실제로는 품질을 보증하지 못하는 경우가 있으므로 주의가 필요합니다.

테스트 케이스 작성법【좋은 예·나쁜 예】

같은 「로그인 기능 테스트」라도 작성 방법에 따라 품질이 크게 달라집니다.

❌ 나쁜 테스트 케이스 예시

항목기재 내용
테스트 IDTC-01
테스트 명로그인 테스트
사전 조건(없음)
실행 단계로그인한다
예상 결과로그인된다

문제점:

  • 「로그인한다」라는 단계로는 무엇을 입력하는지 다른 사람이 재현할 수 없다
  • 「로그인된다」로는 어느 화면으로 이동하면 합격인지 판단할 수 없다
  • 사전 조건이 없으므로 테스트 사용자가 없는 환경에서는 실행할 수 없다

✅ 좋은 테스트 케이스 예시

항목기재 내용
테스트 IDTC-LOGIN-001
테스트 명정상_유효한 인증 정보로 로그인할 수 있는지
사전 조건테스트 사용자(test@example.com / Password123)가 등록되어 있을 것
실행 단계①로그인 화면(/login)을 연다 ②이메일란에 「test@example.com」을 입력한다 ③비밀번호란에 「Password123」을 입력한다 ④「로그인」버튼을 클릭한다
예상 결과대시보드 화면(/dashboard)으로 이동하고 「어서오세요, 테스트 사용자님」이 표시된다
우선순위높음

개선 포인트:

  • 테스트 명에 「정상」이라는 분류를 명기해 테스트 의도가 한눈에 보인다
  • 사전 조건에 구체적인 사용자 정보를 기재해 누구든지 재현할 수 있다
  • 실행 단계를 번호로 세분화해 어느 단계에서 실패했는지 특정하기 쉽다
  • 예상 결과에 「이동 URL」과 「표시 텍스트」를 구체적으로 기술해 판정 기준이 명확하다

정상·비정상·경계값 분류

테스트 케이스를 작성할 때 3가지로 분류해 생각하면 커버리지가 높아집니다.

분류개요로그인 기능 예시
✅ 정상 케이스올바른 입력·조작으로 기대한 대로 동작하는 것유효한 ID·비밀번호로 로그인할 수 있다
❌ 비정상 케이스잘못된 입력·조작에 대해 적절한 에러를 반환하는 것비밀번호 오류·빈 입력·존재하지 않는 ID에서 에러 표시
⚠️ 경계값유효·무효 경계 근처 값에서 버그를 검출하는 것비밀번호가 8~20자 조건이라면 7·8·20·21자를 테스트
💡 왜 경계값을 4점 테스트하는가?:하한과 상한 각각에서 경계 바로 안쪽과 바깥쪽을 확인하는 것이 기본입니다. 「8~20자」라는 조건이라면 7(하한-1)·8(하한 경계)·20(상한 경계)·21(상한+1)을 테스트합니다. >=와 >를 혼동하는 Off-by-one 에러는 경계값에서만 발견할 수 있는 경우가 많습니다.
💡 실무 팁:시간이 부족할 때는 「정상 → 비정상 → 경계값」 순으로 우선순위를 정해 대응합시다. 정상 케이스 없이 비정상만 테스트해도 기능이 제대로 동작하는지조차 알 수 없습니다.

테스트 케이스 작성 시 자주 하는 실수

15년 이상의 현장 경험에서 반복해 목격한 실수 4가지를 소개합니다.

① 예상 결과가 모호해 판정할 수 없다

「정상 동작」「에러 없음」과 같은 예상 결과는 실제로 테스트해도 Pass/Fail을 판정할 수 없습니다. 「○○ 화면이 표시된다」「○○라는 에러 메시지가 표시된다」처럼 구체적인 상태로 기술해야 합니다.

🔍 실무 경험담:15년 이상의 QA 경험에서 리뷰 시 가장 자주 나오는 지적이 「예상 결과가 모호하다」입니다. 거의 매번 나올 정도로 빈번합니다. 「정상 동작」「문제없이 표시」라는 표현은 작성한 본인만 기준을 알고 있는 상태입니다. 예상 결과를 구체적으로 쓰는 습관이 테스트 케이스 품질을 가장 빠르게 높이는 방법입니다.

② 하나의 테스트 케이스에 여러 확인을 담는다

「로그인하고, 프로필을 편집하고, 로그아웃한다」를 하나의 테스트 케이스로 묶으면 도중에 실패했을 때 원인 특정이 어려워집니다. 확인 포인트를 하나씩 분리하면 문제 발생 위치를 쉽게 파악할 수 있습니다.

③ 사전 조건을 기술하지 않아 재현 불가능한 테스트가 된다

「특정 사용자가 아니면 재현되지 않는다」「사전에 데이터를 등록해야 한다」는 조건을 빠뜨리면, 다른 환경이나 다른 담당자가 실행할 때 재현할 수 없습니다. 테스트 시작 상태를 명시하는 것이 중요합니다.

④ 정상 케이스만 작성하고 비정상·경계값을 뒤로 미룬다

「동작만 확인했다」는 상태는 버그의 대부분이 숨어 있는 비정상·경계값을 놓치고 있습니다. 실무에서는 「시간이 없어서 정상만」이 쌓여 릴리즈 후 버그가 발생하는 경우가 적지 않습니다. 비정상 케이스는 처음부터 설계에 포함하는 습관을 길러야 합니다.

자동화 테스트(pytest)에 테스트 케이스 적용하기

이 챕터의 샘플 코드는 GitHub에서도 공개하고 있습니다:github.com/YOSHITSUGU728/automated-testing-portfolio

테스트 케이스에서 자동화 테스트까지의 흐름

테스트 케이스는 설계에서 끝나지 않고, pytest에 녹여냄으로써 자동화 테스트로 지속 활용할 수 있습니다.

① 명세 확인→② 테스트 설계→③ 테스트 케이스→④ pytest 구현→⑤ CI/CD 실행
요구사항·명세서동등분할·경계값 분석정상·비정상·경계값parametrize로 변환GitHub Actions 등

pytest parametrize로 테스트 케이스 표를 코드화하기

작성한 테스트 케이스 목록은 pytest의 @pytest.mark.parametrize를 사용해 그대로 코드화할 수 있습니다. 여기서는 로그인 폼 입력 유효성 검사 함수를 예시로 테스트 케이스 표와 코드의 대응 관계를 보여드립니다.

⚠️ 주의:아래 코드는 「입력값의 형식 확인」을 수행하는 유효성 검사 함수 테스트입니다. 실제 로그인 인증(DB 접근·세션 발급 등)의 테스트가 아닙니다. 실제 로그인 API나 E2E 로그인 테스트는 requests 라이브러리나 Playwright/Selenium을 이용한 별도의 접근이 필요합니다.
import pytest

def validate_login_form(email: str, password: str) -> dict:
    """Validate login form input (format and length checks only).

    Note: This does NOT perform actual authentication.
    It is a utility function for checking input format.
    """
    if not email or not password:
        return {"success": False, "message": "Please enter your email and password"}
    if "@" not in email:
        return {"success": False, "message": "Invalid email format"}
    if len(password) < 8:
        return {"success": False, "message": "Password must be at least 8 characters"}
    return {"success": True, "message": "Input is valid"}

# 테스트 케이스 목록을 그대로 파라미터로 변환
@pytest.mark.parametrize("test_id, email, password, expected_success, expected_message", [
    # 정상 케이스 (유효한 입력 형식)
    ("TC-FORM-001", "test@example.com", "Password123", True,  "Input is valid"),
    # 비정상: 빈 입력
    ("TC-FORM-002", "",                "Password123", False, "Please enter your email and password"),
    ("TC-FORM-003", "test@example.com", "",            False, "Please enter your email and password"),
    # 비정상: 이메일 형식 오류
    ("TC-FORM-004", "invalid-email",   "Password123", False, "Invalid email format"),
    # 경계값: 비밀번호 길이 (조건: 8자 이상)
    ("TC-FORM-005", "test@example.com", "Pass123",    False, "Password must be at least 8 characters"),  # 7자 (하한-1)
    ("TC-FORM-006", "test@example.com", "Pass1234",   True,  "Input is valid"),                          # 8자 (하한 경계값)
])
def test_login_form_validation(test_id: str, email: str, password: str,
                               expected_success: bool, expected_message: str) -> None:
    result = validate_login_form(email, password)
    assert result["success"] == expected_success, f"[{test_id}] 'success' 값이 예상과 다릅니다"
    assert result["message"] == expected_message, f"[{test_id}] 'message' 값이 예상과 다릅니다"
💡 포인트:테스트 ID를 파라미터에 포함하면 실패했을 때 「어느 테스트 케이스가 실패했는지」를 리포트에서 즉시 파악할 수 있습니다. 테스트 케이스 설계와 자동화 테스트 구현을 대응시켜 두면 유지보수성도 향상됩니다.

FAQ

Q. 테스트 케이스와 테스트 명세서의 차이는 무엇인가요?

테스트 명세서는 테스트의 전체 방침·범위·전략을 정리한 상위 문서입니다. 테스트 케이스는 그 안의 개별 검증 절차를 정의한 것입니다. 규모가 큰 프로젝트에서는 「테스트 계획서 → 테스트 명세서 → 테스트 케이스」라는 계층 구조가 되는 경우가 많습니다.

Q. 테스트 케이스는 얼마나 상세하게 써야 하나요?

「다른 사람이 단계를 읽고 동일한 조작을 재현할 수 있는 수준」이 기본적인 기준입니다. 팀 전원이 같은 기능을 잘 알고 있는 경우에는 생략할 수 있는 기술도 있지만, 신규 멤버나 인수인계를 고려하면 어느 정도 구체적으로 써두는 편이 장기적으로 유지보수 비용을 낮출 수 있습니다.

Q. 테스트 케이스의 수는 어느 정도가 적절한가요?

「많을수록 안심」이 아닙니다. 동등 분할이나 경계값 분석 등의 설계 기법을 사용해 대표값으로 좁혀나가는 것이 중요합니다. 테스트 케이스가 너무 많으면 실행·유지보수 비용이 증가하고, 오히려 중요한 테스트가 묻혀버리는 위험이 있습니다. 우선 주요 정상·비정상·경계값 케이스를 망라하는 것을 우선시하고, 필요에 따라 추가하는 접근이 실무에서 다루기 쉽습니다.

Q. 테스트 케이스를 자동화 테스트로 변환하는 기준은?

반복해서 실행하는 것·회귀 테스트로 매번 확인하는 것이 자동화 후보입니다. 한편 「처음만 확인」 「UI 외관을 육안으로 확인」하는 케이스는 수동 테스트가 적합한 경우도 있습니다. 모든 것을 자동화할 필요는 없으며, 비용 대비 효과를 보고 판단합시다.

Q. 명세서가 없는 프로젝트에서의 테스트 케이스 작성은 어떻게 하나요?

명세서가 없는 경우, 기존의 동작을 「사실상의 명세」로 삼아 테스트 케이스로 정리하는 접근이 유효합니다. 개발자에게 인터뷰하거나 탐색적 테스트로 동작을 파악하면서 테스트 케이스를 점진적으로 정비하는 방법이 현장에서 많이 사용됩니다.

📋 정리

  • 테스트 케이스란 「사전 조건·실행 단계·예상 결과」를 하나의 세트로 정리한 검증 단위. 재현성과 추적성이 중요
  • 좋은 테스트 케이스는 누가 읽어도 동일한 조작을 재현할 수 있고, 예상 결과가 구체적으로 판정 가능한 상태로 되어 있다
  • 정상·비정상·경계값 3가지 분류를 의식하면 누락 없는 테스트 케이스 설계가 가능하다
  • pytest의 parametrize와 조합하면 테스트 케이스 목록을 그대로 자동화 테스트로 변환할 수 있다

테스트 케이스의 품질은 그대로 테스트 전체의 품질로 이어집니다. 먼저 가까운 기능(로그인·폼 유효성 검사 등)으로 테스트 케이스를 한 번 작성해 보면 설계 감각이 몸에 배어 갑니다. 테스트 케이스가 있는 상태와 없는 상태에서는 팀의 리뷰 효율과 버그 발견율이 크게 달라지는 것을 실감할 수 있을 것입니다.

제목과 URL을 복사했습니다