사전 테스트 케이스
개념

테스트 케이스

gabury1고친 사람 github-actions[bot]

테스트 케이스는 코드가 맞게 도는지를 한 가지씩 판정해 줍니다. 넣을 값과 나와야 할 값을 미리 적어 둡니다. 코드가 내놓은 값을 그 기대와 맞춰 보고 통과와 실패를 가릅니다. 사람이 손으로 따라 하는 점검 절차 한 장도 같은 이름으로 부릅니다.

쉽고 빠른 이해

무슨 일을 하나 — 기능 하나가 맞게 도는지를 한 가지 경우로 판정합니다. 「장바구니가 2만 원이면 2천 원을 깎아 1만 8천 원이 나와야 한다」가 테스트 케이스 하나입니다.

왜 하나 — 「잘 되는지 봐 주세요」로는 보는 사람마다 판정이 갈립니다. 나와야 할 값을 미리 적어 두면 사람이 보든 프로그램이 보든 같은 판정이 나옵니다. 한 번 적어 둔 케이스는 코드를 고칠 때마다 다시 돌립니다.

어떻게 도나

  1. 돌리기 전에 필요한 준비를 합니다
  2. 정해 둔 값을 넣어 코드를 부릅니다
  3. 나온 값을 기대한 값과 맞춰 통과인지 실패인지 적습니다

대가 — 케이스는 적어 둔 경우까지만 확인해 줍니다. 적지 않은 경우는 깨져도 모릅니다. 코드의 동작이 바뀌면 케이스도 함께 고쳐야 합니다. 케이스가 쌓일수록 손이 갑니다.

상세

이 절의 예는 할인 계산 함수 하나입니다. 장바구니 금액이 2만 원 이상이면 2천 원을 깎아 주는 함수입니다.

시험지의 문항 하나에는 문제와 함께 정답이 정해져 있습니다. 채점하는 사람은 학생이 쓴 답을 정답과 맞춰 보기만 하면 됩니다. 누가 채점해도 맞았는지 틀렸는지가 똑같이 갈립니다.

테스트 케이스는 이 문항 하나에 해당합니다. 어떤 상황에서 어떤 값을 넣으면 어떤 결과가 나와야 하는지를 적은 확인 하나입니다. 「장바구니가 2만 원이면 1만 8천 원이 나와야 한다」가 테스트 케이스 하나입니다.

핵심은 나와야 할 결과를 미리 적는 데 있습니다. 기대가 적혀 있지 않으면 결과를 본 사람이 그럴듯한지를 짐작으로 판단합니다. 적혀 있으면 판정이 「같다」와 「다르다」 둘 중 하나로 줄어듭니다. 이 덕분에 사람 대신 프로그램이 판정할 수 있습니다.

한 번 적은 케이스는 버리지 않고 모아 둡니다. 코드를 고칠 때마다 전부 다시 돌려 전에 되던 것이 여전히 되는지 봅니다. 되던 기능이 다시 깨지지 않았는지 확인하는 이 일이 회귀 테스트입니다.

케이스는 적어 둔 경우까지만 확인해 줍니다. 1만 9천 원짜리 장바구니 케이스가 없으면 그 금액에서 계산이 틀려도 아무도 모릅니다. 그래서 한 기능에 케이스를 여럿 둡니다.

케이스는 코드의 동작을 적어 둔 것이라 동작이 바뀌면 함께 고쳐야 합니다. 할인 기준을 3만 원으로 올리면 2만 원 케이스의 기대 결과도 1만 8천 원에서 2만 원으로 바뀝니다. 케이스가 쌓일수록 이렇게 고칠 곳도 늘어납니다.

테스트 케이스를 이루는 네 부분

케이스 하나는 네 부분으로 나뉩니다. 앞의 2만 원 케이스를 예로 씁니다.

부분 무엇인가 2만 원 케이스에서
사전 조건 돌리기 전에 갖춰져 있어야 하는 상태 할인 기준이 2만 원으로 정해져 있다
입력 코드에 넣는 값이나 하는 행동 금액 20000 을 넣어 할인 함수를 부른다
기대 결과 나와야 하는 값 18000
판정 나온 값을 기대 결과와 맞춰 본 결과 같으면 통과, 다르면 실패

네 칸 가운데 빠지면 안 되는 칸은 기대 결과입니다. 이 칸이 비면 코드를 돌려도 통과인지 실패인지 정할 수 없습니다. 입력만 있고 기대 결과가 없으면 테스트가 아니라 그냥 실행입니다.

사전 조건은 케이스가 기대는 바깥 상태입니다. 데이터베이스에 어떤 상품이 들어 있어야 하는지, 누구로 로그인해 있어야 하는지가 여기 들어갑니다. 이런 준비물을 코드로 만들어 두는 것이 테스트 픽스처입니다. 픽스처를 두면 케이스마다 같은 준비 코드를 되풀이해 적지 않아도 됩니다.

네 부분을 코드로 옮길 때는 흔히 Arrange-Act-Assert 순서를 따릅니다. 테스트 코드를 준비(Arrange), 실행(Act), 확인(Assert)의 세 덩어리로 나누는 방식입니다. 사전 조건은 준비로, 입력은 실행으로, 기대 결과와 판정은 확인으로 갑니다. 이렇게 나눠 두면 어디가 준비이고 어디가 확인인지 한눈에 보입니다.

코드로 적은 테스트 케이스

2만 원 케이스를 파이썬 코드로 옮깁니다. 위쪽 네 줄은 할인 함수입니다. 아래쪽 세 줄은 그 함수를 확인하는 테스트 함수입니다.

Python
def discount(total):
    if total >= 20000:
        return total - 2000
    return total

def test_discount_at_20000():
    price = discount(20000)  # 18000
    assert price == 18000    # 통과

discount(20000) 을 부르는 줄이 입력입니다. 줄 오른쪽 주석은 그 줄의 결과입니다. 첫 줄에는 나온 값을, 둘째 줄에는 판정을 적었습니다. 마지막 줄의 assert 가 나온 값과 기대 결과 18000 을 맞춰 봅니다.

「이 값은 이래야 한다」를 코드로 적어 확인하는 문장이 단언입니다. 단언이 거짓이면 테스트는 거기서 멈춥니다. 그 케이스는 실패로 기록됩니다. 단언이 하나도 없는 테스트 함수는 끝까지 돌아도 아무것도 확인하지 않습니다.

테스트 함수는 사람이 직접 부르지 않습니다. 테스트 러너는 테스트 함수를 찾아 하나씩 부른 뒤 결과를 모아 보여 주는 프로그램입니다. 러너는 이름이 test 로 시작하는 함수를 테스트로 알아보는 경우가 많습니다. 그래서 코드에서는 대개 테스트 함수 하나가 테스트 케이스 하나입니다.

러너가 케이스 하나를 돌리는 순서는 아래 그림과 같습니다.

sequenceDiagram
    participant 러너 as 테스트 러너
    participant 케이스 as 테스트 케이스
    participant 대상 as 할인 함수
    러너->>케이스: 부른다
    케이스->>대상: discount(20000)
    대상-->>케이스: 18000
    Note over 케이스: 기대 결과 18000 과 맞춰 본다
    케이스-->>러너: 통과
    Note over 러너: 통과든 실패든 적고 다음 케이스를 부른다

러너는 케이스 하나가 실패해도 멈추지 않습니다. 다음 케이스를 계속 부른 뒤 끝에 통과와 실패를 모아 보여 줍니다.

파이썬 표준 라이브러리의 테스트 도구 unittest 에서도 케이스 하나는 메서드 하나입니다. 이 도구에는 TestCase 라는 클래스가 있습니다. 이름만 보면 클래스 하나가 케이스 하나처럼 보입니다.

테스트를 짤 때는 TestCase 를 물려받아 테스트 클래스를 만듭니다. 그 클래스 안에 확인할 경우마다 메서드를 하나씩 적습니다. 이 메서드가 테스트 메서드입니다. 러너는 메서드마다 따로 돌려 따로 판정합니다.

케이스를 고르는 법

할인 함수에 넣을 수 있는 금액은 셀 수 없이 많습니다. 전부 넣어 볼 수는 없으니 몇 개만 골라 케이스로 삼습니다. 이 절은 고르는 방법 둘을 다룹니다.

첫째 방법은 대표를 고르는 것입니다. 같은 방식으로 처리될 값들을 한 무리로 보고 무리마다 하나씩 고르는 방법이 동등 분할입니다. 할인 함수라면 「2만 원 이상」과 「2만 원 미만」이 두 무리입니다. 음수처럼 들어오면 안 되는 값도 따로 한 무리로 봅니다.

둘째 방법은 경계를 노리는 것입니다. 실수는 대개 무리가 갈리는 경계에서 납니다. 코드의 >= 를 > 로 잘못 적으면 딱 2만 원에서만 틀린 값이 나옵니다. 경계 값과 그 바로 위아래 값을 따로 케이스로 삼는 이 방법이 경계값 분석입니다.

두 방법으로 고른 값을 한 표에 모읍니다. 줄마다 케이스 하나입니다.

입력 기대 결과 무엇을 보나
30000 28000 할인 무리의 대표
20001 18001 경계 바로 위
20000 18000 경계 값
19999 19999 경계 바로 아래
0 0 할인 없는 무리의 대표(빈 장바구니)
-1 오류를 낸다 들어오면 안 되는 무리의 대표

마지막 줄은 잘못된 입력을 넣는 케이스입니다. 위 코드는 음수를 막지 않아서 -1 을 넣으면 -1 을 돌려줍니다. 따라서 이 케이스는 실패합니다.

음수를 받으면 어떻게 할지는 코드를 짤 때 아무도 정하지 않았습니다. 기대 결과 칸을 채우려는 순간 그 빈 곳이 드러납니다. 케이스를 적는 일이 곧 코드의 동작을 정하는 일이 되는 까닭입니다.

위 표의 줄들은 입력과 기대 결과만 다릅니다. 확인하는 방식은 같습니다. 이럴 때는 표 전체를 테스트 함수 하나에 넘기는 매개변수화 테스트를 짜기도 합니다.

러너는 표의 줄마다 따로 돌려 따로 판정합니다. 그래서 함수는 하나여도 케이스는 줄 수만큼입니다.

결과를 믿을 수 있는 케이스

케이스가 통과했다는 말을 믿으려면 케이스가 세 성질을 지켜야 합니다. 표로 먼저 보고 하나씩 풉니다.

성질 뜻 어기면
한 가지만 확인한다 실패할 이유가 하나뿐이다 실패해도 무엇이 깨졌는지 바로 모른다
홀로 선다 다른 케이스가 먼저 돌았는지에 기대지 않는다 혼자 돌리거나 순서가 바뀌면 결과가 달라진다
되풀이된다 몇 번을 돌려도 같은 판정이 나온다 코드를 안 바꿔도 통과와 실패가 오간다

첫째 성질은 케이스 이름과 이어집니다. 한 가지만 확인하는 케이스는 이름을 「2만 원이면 2천 원을 깎는다」처럼 한 문장으로 지을 수 있습니다. 실패 보고에 이 이름이 뜨면 코드를 열기 전에 무엇이 깨졌는지 압니다.

둘째 성질을 어긴 상태를 테스트 순서 의존성이라고 부릅니다. 주문을 만드는 케이스가 넣은 데이터를 주문 취소 케이스가 꺼내 쓰는 경우입니다. 두 케이스는 그 순서로 돌 때만 통과합니다. 취소 케이스가 취소할 주문을 스스로 만들면 이 의존이 사라집니다.

셋째 성질을 어긴 케이스는 불안정한 테스트입니다. 현재 시각이나 네트워크처럼 돌릴 때마다 달라지는 것에 기대면 이렇게 됩니다. 이런 케이스가 섞이면 사람들이 실패를 「또 그거겠지」 하며 넘기기 시작합니다.

문서로 적는 테스트 케이스

테스트 케이스라는 이름은 코드 밖에서도 씁니다. 사람이 화면을 눌러 보며 확인하는 수동 테스트에서는 케이스를 표 한 장으로 적습니다.

담는 내용은 코드로 적은 케이스와 같습니다. 사전 조건, 해야 할 행동, 기대 결과가 들어갑니다. 테스트 담당자는 절차를 한 줄씩 따라 한 뒤 본 것을 적어 넣습니다.

칸 예
번호 주문-015
제목 2만 원 이상 담으면 할인이 붙는다
사전 조건 일반 회원으로 로그인해 있다. 장바구니가 비어 있다
절차 1만 원짜리 상품 두 개를 담는다. 장바구니를 연다
기대 결과 결제 금액이 1만 8천 원으로 보인다
실제 결과 담당자가 본 것을 적는다
판정 통과 또는 실패

코드로 적은 케이스에 없는 칸은 번호와 실제 결과입니다. 사람이 돌리는 케이스는 무엇을 돌렸는지를 번호로 가리켜야 합니다. 본 것도 기록으로 남겨야 나중에 누가 확인했는지를 따질 수 있습니다.

관련 항목

테스트 케이스를 이루는 구성 요소

단언 · 테스트 픽스처 · 사전 조건 · 기대 결과 · Arrange-Act-Assert · Given-When-Then

테스트 케이스를 묶고 돌리는 도구

테스트 스위트 · 테스트 러너 · 테스트 메서드 · 테스트 클래스 · unittest · pytest · JUnit · xUnit

테스트 케이스를 고르는 기법

동등 분할 · 경계값 분석 · 매개변수화 테스트 · 속성 기반 테스트 · 결정 테이블 테스트 · 상태 전이 테스트

테스트 케이스가 담기는 테스트 종류

단위 테스트 · 통합 테스트 · 종단 간 테스트 · 인수 테스트 · 회귀 테스트 · 스모크 테스트 · 수동 테스트 · 자동 테스트

테스트 케이스의 결과를 흐리는 문제

불안정한 테스트 · 테스트 순서 의존성 · 깨지기 쉬운 테스트 · 공유 픽스처

테스트 케이스가 빠뜨린 경우를 재는 지표

테스트 커버리지 · 분기 커버리지 · 구문 커버리지 · 뮤테이션 테스트

테스트 케이스를 대상 코드와 떼어 놓는 수단

테스트 더블 · 목 객체 · 스텁 · 페이크 객체

테스트 케이스를 먼저 적는 개발 방식

테스트 주도 개발 · 행위 주도 개발 · 인수 테스트 주도 개발

테스트 케이스를 모아 관리하는 문서

테스트 계획 · 테스트 시나리오 · 테스트 절차 · 요구사항 추적 매트릭스

테스트 케이스가 속하는 상위 분류

QA와 테스트 · 소프트웨어 테스트 · 품질 보증

다른 이름: test case · 테스트케이스 · TC