Step Definition
1. 개요
1. 개요
Step Definition은 소프트웨어 테스트 자동화, 특히 행동 주도 개발(BDD) 접근법에서 핵심적인 역할을 하는 구현 코드이다. 이는 Gherkin 언어로 작성된 Feature 파일의 추상적인 시나리오 단계(예: Given, When, Then)를 실제로 실행할 수 있는 프로그래밍 코드로 변환하는 다리 역할을 한다. 주로 Cucumber, SpecFlow, Behat 등의 BDD 프레임워크에서 사용되며, 이러한 도구들이 시나리오의 각 단계를 인식하고 실행할 수 있게 해준다.
Step Definition의 기본 구조는 세 가지 핵심 요소로 이루어진다. 첫째는 단계를 식별하는 키워드(Given, When, Then, And, But)이며, 둘째는 시나리오 단계의 텍스트를 매칭시키기 위한 정규 표현식 또는 Cucumber 표현식이다. 마지막으로 해당 단계가 실행될 때 수행해야 할 구체적인 로직을 담은 함수 본문으로 구성된다. 이 구현 함수는 Java, JavaScript, Python, Ruby 등 프레임워크가 지원하는 다양한 프로그래밍 언어로 작성된다.
간단히 말해, Step Definition은 "무엇을" 테스트할지 기술한 Gherkin 문장과 "어떻게" 테스트할지 정의한 프로그램 코드를 연결함으로써, 실행 가능한 자동화 테스트 스크립트를 완성시키는 구성 요소이다. 이를 통해 비기술적 이해관계자도 읽을 수 있는 시나리오 명세가 실제 테스트 실행으로 이어지는 테스트 자동화의 핵심 메커니즘이 구현된다.
2. 역할과 목적
2. 역할과 목적
Step Definition은 행동 주도 개발(BDD) 접근법의 핵심 구성 요소로, Gherkin 언어로 작성된 시나리오의 추상적인 단계를 실제 실행 가능한 코드로 변환하는 역할을 한다. 이는 Cucumber, SpecFlow, Behat과 같은 BDD 프레임워크에서 사용되며, 테스트의 자동화를 가능하게 한다.
주요 목적은 비기술적 이해관계자도 읽을 수 있는 자연어 형식의 요구사항(Feature 파일)과 기술적인 테스트 코드 사이의 간극을 메우는 것이다. 즉, "Given 사용자가 로그인 페이지에 있다"와 같은 Gherkin 문장이 실제로 브라우저를 열고 특정 URL로 이동하는 코드와 연결되도록 한다. 이를 통해 요구사항, 문서, 테스트 케이스가 단일 진실 공급원으로 통합되어 팀 내 의사소통과 협업을 증진시킨다.
Step Definition은 재사용성을 높이는 데도 기여한다. 동일한 비즈니스 로직을 검증하는 다양한 시나리오에서 동일한 단계(예: "로그인한다")가 반복적으로 사용될 수 있으며, 하나의 Step Definition을 작성함으로써 코드 중복을 방지하고 유지보수성을 향상시킬 수 있다. 결과적으로 Step Definition은 BDD의 실행 가능한 명세라는 핵심 원칙을 실현하며, 소프트웨어의 행위가 명세대로 구현되었는지를 검증하는 실질적인 도구가 된다.
3. 구성 요소
3. 구성 요소
3.1. 키워드
3.1. 키워드
Step Definition의 핵심 구성 요소 중 하나인 키워드는 Gherkin 언어로 작성된 시나리오의 각 단계를 식별하고 연결하는 역할을 한다. 주로 사용되는 키워드는 Given, When, Then이며, 문장의 흐름을 자연스럽게 이어주기 위한 And와 But도 함께 활용된다. 이러한 키워드는 행동 주도 개발의 기본 구조를 반영하여, 테스트의 전제 조건(Given), 실행 동작(When), 기대 결과(Then)를 명확하게 구분하도록 돕는다.
키워드는 Cucumber나 SpecFlow와 같은 BDD 프레임워크가 Feature 파일에 작성된 평문 단계를 실행 가능한 코드와 매칭할 때 중요한 패턴의 일부가 된다. 예를 들어, "Given the user is logged in"이라는 단계는 Given('the user is logged in')과 같은 키워드 패턴을 가진 Step Definition 함수와 연결된다. And와 But 키워드는 직전 단계의 키워드(Given, When, Then 중 하나)를 논리적으로 확장하거나 예외 상황을 추가하는 데 사용된다.
Step Definition을 작성할 때는 이러한 키워드의 의미적 역할을 고려하여 구현해야 한다. Given 단계는 일반적으로 테스트 상태를 설정하고, When 단계는 시스템에 대한 주요 동작을 수행하며, Then 단계는 그 결과를 검증하는 코드를 포함한다. 키워드의 적절한 사용은 테스트 시나리오의 가독성과 유지보수성을 높이는 데 기여한다.
3.2. 정규 표현식 또는 Cucumber 표현식
3.2. 정규 표현식 또는 Cucumber 표현식
정규 표현식 또는 Cucumber 표현식은 Step Definition이 Gherkin 언어로 작성된 시나리오의 특정 문장과 매칭되는지를 판단하는 패턴이다. 이 패턴은 시나리오의 평문 단계와 실제 구현 코드를 연결하는 핵심적인 역할을 한다. 전통적으로는 정규 표현식이 널리 사용되었으나, 최근에는 읽고 쓰기 더 쉬운 Cucumber 표현식이 대안으로 제시되고 있다.
정규 표현식은 강력한 패턴 매칭 기능을 제공하여 복잡한 텍스트 패턴을 정밀하게捕捉할 수 있다. 예를 들어, "^사용자가 \"(.*)\" 검색창에 \"(.*)\"를 입력한다$"와 같은 패턴은 단계 문장에서 따옴표 안의 문자열을 매개변수로 추출하는 데 사용된다. 그러나 정규 표현식 문법은 다소 난해하여 테스트 작성자나 비개발자에게 진입 장벽이 될 수 있다는 단점이 있다.
이에 비해 Cucumber 표현식은 더 직관적인 문법을 사용한다. "사용자가 {string} 검색창에 {string}를 입력한다"와 같이, 중괄호 안에 {string}, {int}, {word} 같은 간단한 매개변수 타입을 명시함으로써 가독성을 높인다. Cucumber 프레임워크는 이 표현식을 내부적으로 정규 표현식으로 변환하여 실행한다. 이 방식은 SpecFlow(.NET)나 Behat(PHP)과 같은 다른 BDD 도구에서도 유사한 개념으로 채택되고 있다.
두 방식 모두 궁극적인 목표는 Feature 파일에 작성된 비즈니스 요구사항을 실행 가능한 테스트 코드로 변환하는 것이다. 선택은 팀의 선호도와 요구되는 패턴의 복잡성에 따라 달라진다. 단순한 매칭에는 Cucumber 표현식이, 매우 복잡하고 유연한 패턴이 필요할 때는 정규 표현식이 더 적합할 수 있다.
3.3. 함수 본문
3.3. 함수 본문
함수 본문은 Step Definition의 핵심으로, Gherkin 언어로 작성된 시나리오의 각 단계가 실제로 어떤 동작을 수행해야 하는지를 프로그래밍 코드로 정의한다. 이 부분은 선택한 프로그래밍 언어(Java, JavaScript, Python, Ruby 등)의 문법에 따라 작성되며, Cucumber나 SpecFlow 같은 BDD 프레임워크는 시나리오 실행 중 해당 단계 키워드와 표현식이 매칭되면 이 함수 본문을 호출한다.
함수 본문 내에서는 일반적으로 애플리케이션과의 상호작용이 이루어진다. 이는 시스템 상태를 설정(Given), 사용자 행동을 시뮬레이션(When), 혹은 예상 결과를 검증(Then)하는 코드를 포함한다. 구체적인 구현은 테스트 대상에 따라 다양하며, 웹 애플리케이션의 경우 브라우저 자동화 도구를, API 테스트의 경우 HTTP 클라이언트 라이브러리를 활용할 수 있다. 함수는 정규 표현식이나 Cucumber 표현식을 통해 추출된 매개변수를 받아 동적인 테스트 데이터를 처리한다.
함수의 설계는 가독성과 재사용성을 고려해야 한다. 복잡한 로직은 별도의 헬퍼 함수나 페이지 객체 모델 같은 디자인 패턴으로 분리하는 것이 좋다. 또한, 각 함수는 하나의 명확한 책임만을 수행하도록 작성되어, 시나리오의 의도를 코드 수준에서도 명확히 반영해야 한다. 이는 유지보수성 높은 테스트 스위트를 구축하는 데 기여한다.
4. 작성 방법
4. 작성 방법
4.1. Given, When, Then 키워드 활용
4.1. Given, When, Then 키워드 활용
Given, When, Then 키워드는 Gherkin 언어로 작성된 시나리오의 각 단계를 분류하고, 그 의미를 명확히 전달하는 데 사용된다. 각 키워드는 시나리오 내에서 특정한 역할을 담당하며, 이에 대응되는 Step Definition을 작성할 때도 동일한 키워드를 사용하여 매핑한다.
Given 키워드는 테스트를 수행하기 위한 사전 조건이나 초기 상태를 설정하는 단계를 정의한다. 예를 들어, "사용자가 로그인되어 있다" 또는 "장바구니에 특정 상품이 추가되어 있다"와 같은 배경 상황을 기술한다. When 키워드는 사용자의 행동이나 시스템에 발생하는 특정 사건을 나타낸다. "사용자가 결제 버튼을 클릭한다" 또는 "관리자가 새로운 상품을 등록한다"와 같은 액션을 표현하며, 테스트의 주요 동작을 수행하는 부분이다. Then 키워드는 When 단계의 실행 결과를 검증하는 데 사용된다. "결제 완료 메시지가 표시된다" 또는 "상품 목록에 새 항목이 나타난다"와 같이 예상되는 결과나 상태 변화를 명시한다.
시나리오를 보다 유연하고 읽기 쉽게 작성하기 위해 And와 But 키워드를 보조적으로 활용할 수 있다. And는 앞선 단계와 동일한 유형의 추가 정보를 연결할 때, But는 예외 상황이나 대조적인 조건을 서술할 때 사용된다. 예를 들어, Given 사용자가 로그인되어 있다 And 프로필 정보가 설정되어 있다와 같이 연속된 Given 조건을 And로 결합할 수 있다. Step Definition을 작성할 때는 이러한 키워드의 논리적 의미를 고려하여, 각 단계가 의도한 대로 시스템 상태를 변경하거나 검증하도록 구현 함수를 구성해야 한다.
4.2. 매개변수 처리
4.2. 매개변수 처리
Step Definition에서 매개변수 처리는 Gherkin 시나리오에 작성된 구체적인 값을 테스트 코드 내부로 전달하여 동적인 테스트를 가능하게 하는 핵심 기능이다. Cucumber나 SpecFlow 같은 BDD 프레임워크는 정규 표현식 또는 Cucumber 표현식을 사용해 Feature 파일의 단계 문장에서 변동되는 부분을 캡처한다.
캡처된 매개변수는 구현 함수의 인자로 자동 전달된다. 예를 들어, "사용자 '홍길동'으로 로그인한다"라는 Gherkin 단계가 있다면, 표현식에서 '홍길동'을 캡처하여 해당 Step Definition 함수의 username 같은 매개변수로 넘겨준다. 이를 통해 동일한 Step Definition으로 다양한 테스트 데이터("홍길동", "김철수" 등)를 사용한 시나리오를 실행할 수 있다. 매개변수는 숫자, 문자열, 데이터 테이블 등 다양한 형태로 전달될 수 있다.
매개변수를 효과적으로 처리하려면 Step Definition의 표현식과 함수 시그니처를 정확히 맞추는 것이 중요하다. 표현식이 캡처하는 그룹의 개수와 순서가 함수가 받는 인자의 개수와 순서와 일치해야 한다. 또한, 정규 표현식을 사용할 때는 캡처 그룹을 명확히 정의하고, Cucumber 표현식을 사용할 때는 간결한 문법(예: {string}, {int})을 활용하여 가독성을 높이는 것이 좋다.
4.3. 재사용성 고려
4.3. 재사용성 고려
Step Definition의 재사용성을 높이는 것은 테스트 코드의 유지보수성과 효율성을 크게 향상시킨다. 핵심은 비슷한 시나리오 단계를 처리하는 함수를 중복 작성하지 않고, 하나의 정의로 여러 Gherkin 문장을 처리할 수 있도록 설계하는 것이다. 이를 위해 정규 표현식이나 Cucumber 표현식을 유연하게 활용하여 다양한 패턴의 단계를 포괄할 수 있게 작성한다. 예를 들어, "사용자가 로그인 페이지에 접속한다"와 "관리자가 로그인 페이지에 접속한다"라는 두 단계는 역할만 다를 뿐 동일한 동작을 수행하므로, "사용자"와 "관리자"를 매개변수로 추출하는 하나의 Step Definition으로 통합할 수 있다.
재사용성을 고려한 설계는 코드의 DRY 원칙을 준수하며, 테스트 요구사항이 변경되었을 때 수정해야 할 지점을 최소화한다. 공통된 전제 조건이나 검증 로직을 별도의 헬퍼 함수나 Hook으로 분리하여 여러 Step Definition에서 호출하도록 구성하는 것도 좋은 방법이다. 또한, Cucumber나 SpecFlow와 같은 BDD 프레임워크는 Background 섹션을 통해 여러 시나리오에 공통으로 적용되는 단계를 정의할 수 있게 지원하며, 이는 Step Definition의 재사용을 촉진하는 중요한 기능이다.
효과적인 재사용을 위해서는 Step Definition의 이름과 표현식을 명확하고 일반적으로 작성해야 한다. 너무 구체적인 구현에 의존하기보다는 추상화 수준을 적절히 유지하여, 비즈니스 로직의 변화에 유연하게 대응할 수 있어야 한다. 이는 궁극적으로 테스트 자동화의 안정성과 생산성을 높이는 데 기여한다.
5. 실행 흐름
5. 실행 흐름
Cucumber나 SpecFlow와 같은 BDD 프레임워크에서 Step Definition의 실행 흐름은 Feature 파일에 작성된 Gherkin 문장과 이를 구현한 코드를 연결하는 매칭 과정을 중심으로 이루어진다. 테스트 실행기가 동작하면, 먼저 Feature 파일을 파싱하여 시나리오 내의 각 단계(Step)를 읽어들인다. 이후, 프로젝트 내에 정의된 모든 Step Definition을 검색하여 현재 단계의 텍스트와 Step Definition에 정의된 정규 표현식 또는 Cucumber 표현식이 일치하는지를 확인한다.
매칭이 성공하면, 해당 Step Definition에 연결된 함수 본문이 실행된다. 표현식에 매개변수가 포함된 경우, 단계 텍스트에서 추출된 값(문자열, 숫자 등)이 함수의 인자로 전달되어 로직 내에서 사용된다. 예를 들어, "사용자 '철수'로 로그인한다"라는 단계는 "사용자 '(.*)'로 로그인한다"라는 표현식과 매칭되어, '철수'라는 값이 함수의 인자로 전달된다. 모든 단계가 순차적으로 실행되고, 마지막 단계의 실행이 완료되면 해당 시나리오의 실행이 종료된다.
실행 중 Step Definition이 발견되지 않거나, 매칭되는 표현식이 여러 개 존재하는 경우에는 오류가 발생한다. 또한, 한 시나리오에서 동일한 Step Definition이 여러 번 호출될 수 있으며, 이는 코드의 재사용성을 높이는 핵심 메커니즘이 된다. 이와 같은 흐름을 통해 비기술자도 이해할 수 있는 Gherkin 시나리오가 실제로 동작하는 자동화 테스트 코드로 변환되어 실행된다.
6. 관련 개념
6. 관련 개념
6.1. Feature 파일
6.1. Feature 파일
Feature 파일은 행동 주도 개발 접근법에서 애플리케이션의 기능적 행동을 명세하는 문서이다. 이 파일은 일반적으로 Gherkin이라는 비즈니스 친화적인 도메인 특화 언어로 작성되며, Cucumber나 SpecFlow와 같은 BDD 프레임워크가 이를 읽고 실행할 수 있는 테스트 스크립트로 해석한다. 파일의 핵심 목적은 개발자, 테스터, 비즈니스 이해관계자 간에 공유할 수 있는 실행 가능한 명세를 제공하여 요구사항과 테스트를 하나의 진실된 소스로 통합하는 데 있다.
하나의 Feature 파일은 특정 기능 단위를 설명하며, Feature, Scenario, Given, When, Then 등의 키워드를 사용해 구조를 정의한다. Feature 키워드로 시작하는 제목과 간략한 설명 아래, 하나 이상의 Scenario 또는 Scenario Outline이 포함된다. 각 시나리오는 특정 조건에서의 사용자 행동과 기대 결과를 Given(초기 조건), When(행동), Then(검증)의 순서로 나열하여 하나의 완전한 테스트 흐름을 구성한다.
Feature 파일에 작성된 각 단계(Step)는 Step Definition이라는 실제 프로그래밍 코드와 매핑되어 실행된다. 예를 들어, Feature 파일에 "Given 사용자가 로그인 페이지에 있다"라는 문장이 있으면, 이는 정규 표현식이나 Cucumber 표현식을 사용해 동일한 텍스트 패턴을 가진 Step Definition 함수와 연결된다. 이렇게 함으로써 사람이 읽을 수 있는 요구사항 명세가 자동화된 테스트 코드로 직접 변환되는 실행 구조가 완성된다.
Feature 파일의 작성은 요구사항의 명확성과 테스트 커버리지를 높이는 데 중점을 둔다. 각 시나리오는 독립적이고 검증 가능해야 하며, 비즈니스 가치를 반영해야 한다. Scenario Outline과 Examples 테이블을 활용하면 다양한 데이터 조합을 가진 동일한 시나리오 흐름을 효율적으로 작성할 수 있어, 테스트 데이터 주도 접근법을 지원한다.
6.2. Cucumber 프레임워크
6.2. Cucumber 프레임워크
Cucumber는 행동 주도 개발을 지원하는 테스트 자동화 도구이자 프레임워크이다. 이 프레임워크의 핵심은 비기술자와 기술자가 공통으로 이해할 수 있는 Gherkin 언어로 작성된 시나리오와, 이를 실제로 실행하는 프로그래밍 코드를 연결하는 것이다. Step Definition은 이 연결을 담당하는 구체적인 구현 코드로, Cucumber 프레임워크가 Gherkin 문장을 해석하고 실행할 수 있게 만든다.
Cucumber는 Java, JavaScript, Python, Ruby 등 여러 프로그래밍 언어를 지원하며, SpecFlow는 .NET 환경을 위한 Cucumber 스타일의 프레임워크이다. PHP 환경에서는 Behat이 유사한 역할을 수행한다. 이러한 프레임워크들은 모두 Given, When, Then과 같은 키워드로 시작하는 자연어 문장을 특정 코드 블록에 매핑하는 동일한 원리를 공유한다.
Cucumber 프레임워크의 실행 흐름은 일반적으로 Feature 파일에 정의된 시나리오를 읽는 것으로 시작한다. 프레임워크는 각 시나리오의 단계를 순차적으로 실행하며, 각 단계에 해당하는 Step Definition을 찾아 그 안에 구현된 함수 본문을 수행한다. 이 과정에서 정규 표현식이나 Cucumber 표현식을 사용해 단계 문장에서 동적 값을 추출하여 테스트 코드의 매개변수로 전달할 수 있다.
6.3. BDD(Behavior-Driven Development)
6.3. BDD(Behavior-Driven Development)
BDD는 행동 주도 개발의 약자로, 소프트웨어 개발 방법론 중 하나이다. 이 방법론은 기술적 용어 대신 비즈니스 이해관계자, 개발자, 테스트 담당자 모두가 이해할 수 있는 자연어를 사용하여 소프트웨어의 기대 행동을 정의하고 문서화하는 데 중점을 둔다. Step Definition은 BDD의 핵심 실행 도구로서, 이러한 자연어로 작성된 시나리오의 각 단계를 실제 코드로 변환하는 역할을 한다.
BDD의 실천 과정에서는 Gherkin 언어로 Feature 파일을 작성한다. 이 파일에는 Given, When, Then 등의 키워드를 사용한 시나리오가 포함되어 있으며, 각 줄은 소프트웨어의 특정 행동을 서술한다. Step Definition은 이러한 추상적인 서술문을 구체적인 프로그래밍 명령어로 매핑함으로써, 문서화된 요구사항이 바로 실행 가능한 테스트로 기능하도록 만든다.
이 접근 방식은 단순한 테스트 자동화를 넘어, 팀 내의 명확한 의사소통과 공유된 이해를 촉진한다. 요구사항이 실행 가능한 명세로 변환되므로, 구현 과정에서 요구사항이 왜곡되거나 누락되는 것을 방지하고, 소프트웨어가 실제로 기대한 대로 동작하는지 지속적으로 검증할 수 있다. Cucumber, SpecFlow, Behat 등의 프레임워크가 BDD를 지원하는 대표적인 도구이다.
따라서 Step Definition은 BDD 프로세스에서 비즈니스 요구사항과 기술적 구현을 연결하는 결정적인 가교라고 할 수 있다. 이를 통해 작성된 시나리오는 살아있는 문서 역할을 하며, 소프트웨어의 기능이 명세대로 정확히 구현되었는지를 자동으로 검증하는 기반을 제공한다.
7. 여담
7. 여담
Step Definition은 BDD 접근법을 실제 코드로 연결하는 핵심적인 다리 역할을 하지만, 그 구현과 관리 과정에서 여러 실용적인 고려사항이 존재한다. 우선, Step Definition의 품질은 테스트 스위트의 유지보수성에 직접적인 영향을 미친다. 지나치게 구체적이고 상황에 종속된 Step Definition을 작성하면, 사소한 시나리오 변경에도 코드 수정이 필요해져 유연성을 떨어뜨린다. 반대로 너무 추상적이고 일반화된 Step Definition은 가독성을 해치고 의도를 파악하기 어렵게 만든다. 따라서 '의도를 명확히 드러내는' 수준의 추상화를 유지하는 것이 중요하다.
Step Definition 작성 시 흔히 발생하는 문제는 코드 중복이다. 여러 시나리오에서 유사한 단계(예: '로그인한다', '장바구니에 담는다')가 반복되면, 각각을 위한 별도의 Step Definition을 만드는 대신 매개변수를 활용해 하나의 정의로 통합해야 한다. Cucumber 표현식이나 정규 표현식을 효과적으로 사용하면 다양한 문장 패턴을 단일 구현으로 처리할 수 있어 재사용성을 크게 높인다. 또한, Hook을 활용하여 시나리오 실행 전후에 공통으로 필요한 설정이나 정리 작업을 처리함으로써 Step Definition 본문을 간결하게 유지할 수 있다.
실제 프로젝트에서 Step Definition은 Feature 파일에 작성된 비즈니스 요구사항과 구현 코드 사이의 '계약'으로 작동한다. 이 계약이 명확하지 않으면, 비개발자 이해관계자와 개발자 간의 소통에 간극이 생길 수 있다. 따라서 Step Definition의 함수명과 매개변수명은 비즈니스 도메인 용어를 반영해야 하며, 내부 구현은 가능한 한 도메인 로직을 직접 호출하는 방식으로 작성되어야 한다. 이는 테스트 코드가 단순한 UI 자동화 스크립트가 아니라, 시스템의 실제 동작을 검증하는 실행 가능한 명세로서의 가치를 갖게 한다.
