당신의 CI 파이프라인 중 얼마나 많은 부분이 삭제하기 두려운 Cucumber 시나리오로 채워져 있습니까?
요약
CI 파이프라인에서 버그를 잡지 못하면서 실행 시간만 잡아먹는 오래된 Cucumber 시나리오의 위험성을 경고합니다. 이러한 테스트는 피드백 지연, 불안정성 증가, 신뢰도 저하 등 기술 부채로 작용하므로 정기적인 감사가 필요합니다.
핵심 포인트
- 실패하지 않는 오래된 테스트는 자산이 아닌 부채임
- 비대한 테스트 스위트는 개발 피드백 루프를 느리게 만듦
- 테스트의 불안정성(Flakiness)은 팀의 신뢰를 침식함
- 유지보수 비용과 리팩터링 시 발생하는 세금 증가
- 정기적인 테스트 감사(Audit)를 통한 최적화 필요
CI 작업 시간이 또 28분을 찍었습니다. 또 말이죠.
당신은 비대해진 통합 테스트 (integration test)나 느린 환경 구축 (environment spin-up)을 탓할 생각으로 소요 시간 보고서를 불러옵니다. 하지만 대신 가장 긴 단계가 당신을 빤히 쳐다봅니다. 바로 몇 달 동안, 어쩌면 몇 년 동안 실제 버그를 잡아내지 못한 Cucumber 피처 파일 (feature files)들의 집합입니다. 이 파일들은 모든 커밋마다 실행되며, 초록색 체크 표시가 계속 이어지지만, 팀원들은 느린 파이프라인에 대해 투덜대면서도 아무도 그것들을 건드릴 엄두를 내지 못합니다.
대부분의 팀은 이러한 시나리오를 문서처럼 취급합니다. 누군가는 Gherkin 파일이 마치 법적 계약서라도 되는 양 "이것들이 시스템을 설명해 준다"라고 말한 적이 있습니다. 다른 이들은 매몰 비용 (sunk cost)에 집착합니다. 1년 전, 한 팀 전체가 두 번의 스프린트 (sprint) 동안 문법을 다듬고 단계 정의 (step definitions)를 맞추며 이 시나리오들을 작성하는 데 시간을 쏟았기 때문입니다. 그것들을 삭제하는 것은 낭비를 인정하는 것처럼 느껴질 것입니다.
경험 많은 엔지니어들은 이를 다르게 봅니다. 그들은 절대 실패하지 않는 시나리오를 매 푸시 (push)마다 비용을 지불하고 있는 부채 (liability)로 취급합니다. 중립적인 것이 아니라, 부채입니다. 컴퓨팅 사이클 (compute cycles), 개발자의 주의력, 불안정한 테스트 디버깅 (flake-debugging) 시간, 그리고 파이프라인에 대한 신뢰를 서서히 갉아먹는 조용한 대가 말입니다.
원칙은 명확합니다. 만약 테스트가 지난 몇 번의 스프린트 동안 실패하지 않았다면, 당신은 이미 그 비용을 전액 지불하고 있으면서 아무런 보상도 받지 못하고 있는 것입니다. 이것이 모든 초록색 테스트를 삭제해야 한다는 뜻은 아닙니다. 하지만 메모리 누수 (memory leak)를 조사할 때와 같은 진지함으로 감사 (audit)를 수행해야 한다는 뜻입니다.
초록색 벽이 실제로 치르는 비용
그 피해는 추상적이지 않습니다. 오래된 시나리오로 비대해진 파이프라인은 다섯 가지 구체적인 방식으로 당신에게 해를 끼칩니다.
첫째, 피드백이 느려집니다. 푸시와 결과 사이의 매 추가 분은 개발자에게 머지 (merge)해도 안전하다는 것을 알려주는 루프를 늘립니다. 팀 전체로 곱해보면, 당신은 기다리는 데 매주 몇 시간을 허비하고 있는 것입니다.
둘째, 불안정성 (flakiness)이 증가합니다. 시나리오가 많아지면, 단 하나의 불안정한 환경 변수 (environment variable)가 회귀 (regression)가 전혀 아닌 몇 가지 실패를 만들어낼 수 있습니다. 엔지니어들은 재시도하는 법을 배우고, 그다음에는 무시하는 법을 배웁니다.
셋째, 신뢰가 침식됩니다. 만약 테스트 스위트 (suite)의 절반이 형식적인 것이라면, 실제 실패가 발생하더라도 프로덕션 (production)에 도달할 때까지 "그냥 또 다른 불안정한 테스트일 뿐이야"라며 무시될 수 있습니다.
넷째, 유지보수 비용이 가중됩니다. 버튼의 이름을 바꾸거나 흐름 (flow)을 재구성할 때, 누군가는 여전히 그에 대응하는 단계 정의 (step definitions)를 업데이트해야 합니다. 오래된 시나리오들은 리팩터링 (refactor)을 할 때마다 일종의 세금처럼 작용합니다.
다섯째, 커버리지 (coverage)를 추론할 수 있는 능력을 상실하게 됩니다. 슬림하고 정교하게 구성된 테스트 세트는 무엇이 보호되고 있는지에 대해 명확한 이야기를 들려줍니다. 반면 소음으로 가득 찬 벽은 무언가를 제거했을 때 실제로 무엇이 깨질지 알 수 없게 만듭니다.
부패를 확인하는 방법
측정할 수 없는 것은 고칠 수 없습니다. 첫 번째 단계는 CI로부터 실행 데이터를 수집하는 것입니다. 대부분의 테스트 러너 (test runner)는 시나리오 이름과 결과를 포함하는 JSON 또는 JUnit 보고서를 생성합니다. 현재 설정에서 이를 지원하지 않는다면, 데이터를 캡처하기 위해 CI 스크립트를 몇 줄 작성할 가치가 있습니다.
가장 쉽게 해결할 수 있는 부분은 전혀 실행되지 않는 시나리오들입니다. 기능이 재작성된 후 남겨진 피처 파일 (feature files), 더 이상 존재하지 않는 페이지를 참조하는 시나리오, 도달할 수 없는 단계 정의 (step definitions) 등이 이에 해당합니다. 테스트 러너가 이를 조용히 건너뛰기 때문에 눈에 보이지 않습니다.
다음은 피처 파일에 있는 모든 시나리오 이름을 최근에 실제로 실행된 CI 보고서 내용과 비교하는 TypeScript 유틸리티입니다. 이 코드는 의도적으로 최소한의 기능만 담고 있습니다. 실제 프로덕션 (production) 환경에서 사용하려면 제대로 된 Gherkin 파서 (parser)와 고유 ID가 필요하겠지만, 이 코드를 통해 전체적인 형태를 파악할 수 있습니다.
import fs from 'fs';
import path from 'path';
...
이를 한 번 실행하면 즉시 삭제할 수 있는 후보 목록을 얻을 수 있습니다. 시나리오가 실행되지 않고 있다면, 그것은 아무것도 보호하고 있지 않은 것입니다. 삭제하십시오.
더 어려운 카테고리는 실행은 되지만 절대 실패하지 않는 시나리오입니다. 이를 위해서는 이력 데이터 (window of history)가 필요합니다. 작은 Python 스크립트를 사용하여 보관된 보고서 디렉토리를 파싱하고, 예를 들어 지난 90일 동안 실패 횟수가 0인 시나리오를 찾아낼 수 있습니다. 로직은 간단합니다. 고유한 시나리오 ID별로 통과/실패 횟수를 누적하고, failure_count == 0인 항목을 표시하면 됩니다. 전체 스크립트를 여기에 붙여넣지는 않겠지만, 20줄 정도면 작성할 수 있습니다.
오래된(stale) 목록을 확보했다면, 한꺼번에 모든 것을 삭제하여 경보를 울리게 하지 마세요. 하위 5%를 먼저 제거하고 몇 번의 사이클을 지켜보세요. 대개 파이프라인이 조금 더 빨라지는 것 외에는 아무런 변화가 없을 것입니다.
단순한 흐름에 부과되는 Cucumber 세금
Gherkin에서 로그인 시나리오가 어떻게 생겼는지, 그리고 그 주변에 얼마나 많은 격식(ceremony)이 따르는지 당신은 알고 있습니다. Background 단계가 포함된 feature 파일, 여러 파일에 흩어져 있는 대여섯 개의 단계 정의(step definitions), 드라이버 관리를 위한 훅(hooks), 어쩌면 커스텀 파라미터 타입(custom parameter types)까지 말이죠. 이 모든 것이 고작 "두 개의 필드를 채우고, 버튼을 클릭하고, 대시보드를 확인한다"라는 말을 하기 위해 존재합니다.
이제 동일한 의도를 Playwright 테스트로 표현한 것을 살펴보세요.
import { test, expect } from '@playwright/test';
test('successful login', async ({ page }) => {
...
이것은 협업을 위한 실천 방법으로서의 BDD (Behavior-Driven Development)를 비난하는 것이 아닙니다. 많은 팀이 — 도구가 지금과는 달랐던 수년 전부터 — UI 테스트를 작성하기 위해 Cucumber를 사용해 왔으며, 그 테스트들이 이제는 프레임워크 자체가 더 명확하게 설명할 수 있는 상호작용(interactions)을 그저 장황하게 감싸고 있는 래퍼(wrapper)일 뿐이라는 점을 인식하는 것입니다.
단계 정의(step definitions)가 유기적으로 늘어날 때 문제는 더욱 심각해집니다. "Given I
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기