Given-When-Then: 정의, 시나리오 구조 및 예제

저자: IT Sectr 게시일: 2026-04-10 읽는 시간: 8 분

Given-When-Then은 테스트 시나리오를 설명하기 위한 구조적 패턴으로, BDD가 domain-driven design에서 차용하여 Behaviour-Driven Development에 맞게 조정한 것입니다. 이 형식은 시나리오를 세 가지 논리적 부분(전제조건(Given), 동작(When), 예상 결과(Then))으로 나눕니다. Martin Fowler(2023)에 따르면, Given-When-Then은 단순한 테스트 형식이 아니라 구현을 시작하기 전에 요구사항 분석과 시나리오 설계를 체계화하는 사고 도구입니다.

핵심 요점

  • Given-When-Then — 세 블록(컨텍스트, 동작, 결과)으로 구성된 시나리오 설명 패턴
  • Given은 테스트 대상 동작 실행 전 시스템의 초기 상태와 데이터를 설정합니다
  • When은 테스트 대상 로직을 트리거하는 이벤트 또는 동작을 설명합니다
  • Then은 예상되는 상태 변경 또는 반환 값을 검증합니다
  • Arrange-Act-Assert — 단위 테스트에서 Given-When-Then의 동등물이지만 비즈니스 언어 지향성이 없습니다

Given-When-Then이란?

Given-When-Then은 Dan North가 2006년 Behavior-Driven Development 방법론의 일부로 처음 공식화한 동작 설명 패턴입니다. 이 패턴은 임의의 순서로 전제조건, 동작 및 검증이 혼합되어 있는 경우가 많은 비구조화된 테스트 시나리오 설명의 문제를 해결합니다.

패턴의 주요 아이디어는 세 블록 간의 책임 분리입니다. 각 블록은 시나리오의 정확히 한 가지 측면(이전 상태, 이벤트 중, 이후 검증)을 담당합니다. 이렇게 하면 시나리오를 읽고, 검증하고, 자동화할 수 있습니다. Cucumber 프레임워크 개발자의 연구(2024)에 따르면, Given-When-Then 패턴을 엄격히 따르는 시나리오는 새 팀원이 이해하는 데 42% 더 적은 시간이 소요됩니다.

패턴의 기원

Dan North는 TDD의 테스트 공식화Test-by-Example 방법론(Brian Marick이 창안)에서 세 부분으로 구성된 구조의 아이디어를 차용했습니다. Marick은 동시에 테스트 역할을 하는 예제( examples)를 통해 요구사항을 설명할 것을 제안했습니다. Given-When-Then은 이 아이디어를 공식화하여 비구조화된 예제를 반복 가능한 패턴으로 전환했습니다.

적용 범위

Given-When-Then 패턴은 Gherkin의 BDD 시나리오뿐만 아니라 JUnit, XCTest 및 기타 프레임워크의 일반적인 단위 테스트에도 적용됩니다. 테스트를 세 블록으로 나누는 코드 내 주석은 테스트 베이스의 가독성을 향상시키는 일반적인 관행입니다. Google은 저서 『Software Engineering at Google』(2020)에서 이 접근 방식을 권장합니다.

세 블록의 구조

Given-When-Then의 각 블록에는 엄격하게 정의된 의미와 작성 규칙이 있습니다. 이러한 규칙을 위반하면 자동화하거나 이해하기 어려운 시나리오가 생성됩니다.

Given: 전제조건

Given 블록은 테스트 대상 동작을 실행하기 전 시스템의 상태를 설명합니다. 여기에는 기존 객체(사용자, 주문, 설정), 활성 상태(인증됨, 네트워크 연결됨) 및 데이터의 초기 값이 포함됩니다. 각 Given은 검증 가능해야 합니다. 시스템 상태가 Given과 일치하지 않으면 시나리오를 건너뛰거나 테스트 환경을 미리 준비해야 합니다.

When: 동작

When 블록은 테스트 대상 동작을 시작하는 단일 이벤트를 설명합니다. 메서드 호출, 버튼 클릭, 알림 수신 또는 서버 응답일 수 있습니다. 핵심 규칙은 시나리오당 하나의 When입니다. 동작 시퀀스를 확인해야 하는 경우 When 체인이 아니라 별도의 시나리오를 만듭니다.

kotlin
// Given: 테스트 데이터 생성
val user = User(email = "test@example.com", balance = 500.0)
val product = Product(price = 150.0)

// When: 동작 실행
val result = PurchaseUseCase().buy(user, product)

// Then: 결과 검증
assertEquals(PurchaseResult.Success, result)
assertEquals(350.0, user.balance)

Then: 예상 결과

Then 블록은 시스템이 예상 상태로 전환되었는지 확인합니다. 여기에는 반환 값, 객체 상태 변경, 외부 서비스 호출(모크 검증을 통해) 및 UI 변경이 포함됩니다. 각 Then 블록에는 여러 검증이 포함될 수 있지만 모두 단일 동작과 관련됩니다.

Given-When-Then과 Arrange-Act-Assert

Given-When-ThenArrange-Act-Assert(AAA)는 동일한 세 부분 패턴의 두 가지 변형이지만 대상 사용자가 다릅니다. 차이점을 이해하면 특정 작업에 적합한 형식을 선택하는 데 도움이 됩니다.

측면Given-When-ThenArrange-Act-Assert
기원BDD, 비즈니스 분석단위 테스트
언어자연어(Gherkin)코드(Kotlin, Swift, Java)
대상전체 팀 + 클라이언트개발자
세부 수준높은 수준상세
자동화Cucumber, SpecFlowJUnit, XCTest, Mockito

Given-When-Then을 사용해야 하는 경우

Given-When-Then 패턴은 클라이언트나 분석가와 논의하는 시나리오(기능의 승인 기준, 사용 사례, 회귀 검사)에 최적입니다. Gherkin 구문을 사용하면 프로그래밍 지식 없이도 이러한 시나리오를 작성할 수 있습니다.

Arrange-Act-Assert를 사용해야 하는 경우

Arrange-Act-Assert는 특정 메서드나 클래스를 검증하는 단위 테스트의 자연스러운 선택입니다. AAA 형식은 추가 프레임워크가 필요하지 않으며 모든 프로그래밍 언어에서 작동합니다. iOS 개발의 경우 Apple은 XCTest 문서(2024)에서 AAA를 권장합니다.

Kotlin 시나리오 예제

Android 애플리케이션용 Kotlin의 Given-When-Then 실제 예제를 살펴보겠습니다. 첫 번째 예제는 MockK을 사용한 쇼핑 카트 테스트입니다. 두 번째는 푸시 알림 로직 테스트입니다.

예제 1: 쇼핑 카트

kotlin
class CartTest {
    fun `apply discount when total exceeds threshold`() {
        // Given
        val cart = Cart()
        cart.addItem(Item("Laptop", price = 1000.0))
        cart.addItem(Item("Mouse", price = 50.0))
        val discount = DiscountCalculator(0.1)

        // When
        val total = discount.applyIfEligible(cart)

        // Then
        assertEquals(945.0, total)
        assertTrue("Discount was not applied", total < 1050.0)
    }
}

예제 2: 코루틴을 사용한 푸시 알림

두 번째 예제는 비동기 코드를 사용한 Given-When-Then을 보여줍니다. 여기서 Given은 Firebase Cloud Messaging의 상태를 설정하고, When은 푸시 알림 수신, Then은 처리 검증을 수행합니다.

kotlin
class PushNotificationTest {
    fun `handle push notification when app in background`() = runTest {
        // Given
        val prefs = mockk<SharedPreferences>()
        every { prefs.getString("token", null) } returns "fcm-token-abc"
        val handler = PushHandler(prefs)

        // When
        val data = RemoteMessage().apply {
            putData("type", "order_update")
            putData("order_id", "123")
        }
        val result = handler.handleNotification(data)

        // Then
        assertEquals(NotificationAction.OpenOrder("123"), result)
    }
}

예제 3: 인증을 위한 Gherkin 시나리오

세 번째 예제는 승인 테스트 컨텍스트에서 Given-When-Then을 보여주는 Gherkin의 BDD 시나리오입니다:

gherkin
Feature: User Authorization
  Scenario: User cannot login with expired token
    Given the user has an expired refresh token
    When they try to access the protected profile screen
    Then they should see the login screen
    And the app should clear all cached data

시나리오 작성 모범 사례

Given-When-Then을 효과적으로 적용하려면 몇 가지 검증된 관행을 따라야 합니다. 이러한 관행은 시나리오의 가독성, 유지 관리 용이성 및 자동화를 보장합니다.

시나리오당 하나의 When

엄격한 규칙: 하나의 시나리오 — 하나의 동작. 여러 개의 When 시퀀스를 확인해야 하는 경우 이전 결과가 다음의 전제 조건이 되는 여러 시나리오를 만듭니다. 이렇게 하면 시나리오가 원자적이고 이해하기 쉬워집니다.

Given에서 구체적인 데이터를 피하십시오

Given은 본질을 설명해야 하며 구체적인 숫자가 아닙니다. 「Given 사용자 Ivanov, 잔액 500루블」 대신 「Given 잔액이 충분한 사용자」로 작성합니다. 구체적인 데이터는 Examples 테이블이 있는 Scenario Outline으로 이동합니다. 이렇게 하면 시나리오가 보편적이고 재사용 가능해집니다.

  • Then은 측정 가능한 어설션으로 작성하십시오 — 「사용자는 로그인 화면을 봐야 합니다」, 「사용자가 리디렉션되어야 합니다」가 아닙니다
  • 동일한 유형의 단계에는 And를 사용하십시오 — 여러 Given이 필요한 경우 And로 결합하고 두 번째 Given을 만들지 마십시오
  • 추상화 수준을 혼합하지 마십시오 — Given-When-Then은 동일한 수준(비즈니스 또는 기술 중 하나)이어야 하며 혼합되지 않아야 합니다
  • 시나리오의 이유를 문서화하십시오 — .feature 파일 시작 부분의 비즈니스 규칙 설명이 포함된 주석이 컨텍스트에 도움이 됩니다

CI/CD 파이프라인의 Given-When-Then

Given-When-Then 시나리오를 지속적 통합 파이프라인에 통합하면 문서에서 회귀 방지로 전환됩니다. 모바일 프로젝트의 각 병합 요청은 자동으로 BDD 시나리오를 실행하고 하나 이상의 시나리오가 실패하면 병합을 차단합니다.

시나리오 자동 실행

Android용 Cucumber의 BDD 시나리오는 Gradle 태스크 ./gradlew cucumber를 통해 실행됩니다. iOS(Quick/Nimble)의 경우 xcodebuild test를 통해 실행됩니다. CI 시스템(GitHub Actions, GitLab CI, Bitrise)에서 BDD 테스트는 에뮬레이터 또는 실제 디바이스에서 실행됩니다. 보고서는 관리자가 이해할 수 있는 HTML 형식으로 생성됩니다: 녹색 시나리오는 통과, 빨간색은 단계를 표시한 실패입니다.

저장소의 살아있는 문서

.feature 파일은 코드와 함께 저장소에 저장되며 코드 리뷰를 거칩니다. 분석가는 개발 시작 전에(BDD 우선) 새 시나리오가 포함된 병합 요청을 생성합니다. 개발자는 이러한 시나리오를 통과시키기 위해 단계 정의와 구현을 작성합니다. 모든 시나리오가 통과하면 기능이 완료됩니다. Gojko Adzic의 저서 『Specification by Example』(2011)에 설명된 이 접근 방식은 요구사항을 실행 가능한 결과물로 변환합니다.

자주 묻는 질문

Given-When-Then은 Arrange-Act-Assert와 같은 것인가요?

구조적으로는 네, 동일한 세 부분 패턴입니다. 차이는 대상 사용자에 있습니다: Given-When-Then은 비즈니스 언어 중심으로 BDD에서 Gherkin과 함께 사용되는 반면, Arrange-Act-Assert는 단위 테스트를 위한 기술적 형식입니다. 선택은 컨텍스트와 팀에 따라 다릅니다.

Then 블록에는 몇 개의 검증을 포함할 수 있나요?

제한은 없지만 Then당 3~5개 이하의 검증을 권장합니다. 검증이 더 많으면 시나리오가 하나의 동작에서 너무 많은 것을 확인하고 있을 수 있습니다. 다른 Then을 가진 여러 시나리오로 분할하세요.

Given-When-Then을 Gherkin으로 작성해야 하나요?

아니요. 이 패턴은 모든 테스트 프레임워크에서 사용할 수 있으며, 주석이나 빈 줄로 테스트를 세 블록으로 나누기만 하면 됩니다. Gherkin은 Cucumber 또는 SpecFlow용 .feature 파일 형식으로 시나리오를 작성하는 경우에만 필요합니다.

Given의 긴 전제조건은 어떻게 처리하나요?

반복되는 전제조건은 Background(Gherkin) 또는 @Before 메서드(JUnit)로 추출하는 것이 좋습니다. 전제조건이 복잡한 경우 Builder 패턴을 사용하여 테스트 데이터를 만듭니다. 이렇게 하면 Given을 짧고 읽기 쉽게 유지할 수 있습니다.

When 블록이 비어 있어도 되나요?

아니요. When은 동작을 설명하는 필수 블록입니다. 시나리오가 동작 없이 상태만 확인하는 경우(예: 「애플리케이션 로드 시 데이터가 캐시되어야 함」), When은 트리거를 설명합니다: 「애플리케이션이 시작될 때」.

요약

  • Given-When-Then — 시나리오 설명을 위한 세 부분 패턴: 전제조건, 동작, 예상 결과
  • Given은 컨텍스트와 초기 상태를 설정하고, When은 유일한 동작, Then은 결과 검증
  • Arrange-Act-Assert와 Given-When-Then은 대상 사용자와 추상화 수준이 다른 동일한 패턴
  • 이 패턴은 BDD(Gherkin, Cucumber)와 일반적인 단위 테스트(JUnit, XCTest)에 주석을 통해 적용됩니다
  • 핵심 규칙: 시나리오당 하나의 When — 각 동작은 개별적으로 검증되어야 함
  • 반복되는 전제조건은 중복을 줄이기 위해 Background 또는 @Before 메서드로 추출됩니다
  • Examples 테이블이 있는 Scenario Outline은 코드 중복 없이 다양한 데이터 세트로 Given-When-Then을 매개변수화할 수 있습니다

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기