Pest 테스트 케이스 명명 규칙: 가독성과 유지보수성을 높이는 실용적 지침

테스트 코드는 단순한 검증 도구가 아니라 시스템의 행동을 설명하는 생동하는 문서입니다. 특히 Pest는 PHP에서 BDD 중심의 간결한 문법을 제공하므로, 명확하고 일관된 명명 방식은 팀 협업과 장기적인 코드 품질에 직접적인 영향을 미칩니다.

행동 중심 명명 전략

Pest의 it() 함수는 자연어 스타일로 테스트 의도를 표현하기에 적합합니다. 다음 구조를 권장합니다:

// 권장: 조건과 결과를 명시
it('redirects to dashboard after successful login')
    ->post('/login', ['email' => 'admin@test.dev', 'password' => 'pass123'])
    ->assertRedirect('/dashboard');

// 비권장: 추상적이거나 구현 세부사항 포함
test('testLoginSuccess') { /* ... */ }

동사 기반 동작 표현

테스트 이름은 반드시 동사로 시작해야 하며, 해당 테스트가 무엇을 검증하는지 한눈에 파악할 수 있어야 합니다:

  • validates: 입력 유효성 검사 — it('validates email format')
  • retrieves: 데이터 조회 — it('retrieves active subscriptions')
  • blocks: 접근 차단 — it('blocks unverified users from payment flow')
  • enqueues: 작업 큐 등록 — it('enqueues notification on order confirmation')
  • serializes: 직렬화 동작 — it('serializes product variant with pricing')

계층적 컨텍스트 구성

describe()를 사용해 논리적 계층을 형성하면, 실행 결과 출력에서도 구조가 명확해집니다:

describe('SubscriptionManager', function () {
    describe('::activate()', function () {
        it('activates subscription when trial period ends')
            ->given(new TrialEndedEvent())
            ->when(fn() => $this->manager->activate($subscription))
            ->then(fn($sub) => expect($sub->status)->toBe('active'));

        describe('with overdue invoice', function () {
            it('does not activate until payment is settled')
                ->given(new OverdueInvoiceDetectedEvent())
                ->when(fn() => $this->manager->activate($subscription))
                ->then(fn($sub) => expect($sub->status)->toBe('pending_payment'));
        });
    });
});

출력 예시:

SubscriptionManager > ::activate() > activates subscription when trial period ends
SubscriptionManager > ::activate() > with overdue invoice > does not activate until payment is settled

데이터 기반 테스트의 명명

파라미터화된 테스트에서는 각 케이스가 무엇을 검증하는지를 이름에 반영하세요:

it('formats currency correctly for {locale}', function ($locale, $amount, $expected) {
    expect(formatCurrency($amount, $locale))->toBe($expected);
})->with([
    'korean_won' => ['ko_KR', 100000, '₩100,000'],
    'us_dollar'  => ['en_US', 99.99, '$99.99'],
]);

상태 및 의도 표시 접두사

특정 상태나 개발 단계를 나타내는 접두사를 활용해 테스트의 의도를 즉각 전달할 수 있습니다:

  • ⚠️ skips legacy endpoint migration test — 일시적으로 건너뜀
  • 🧪 verifies new rate-limiting algorithm — 실험적 기능
  • 🔍 confirms edge-case behavior in refund workflow — 디버깅 목적

비즈니스 용어 통합

기술 용어보다 도메인 언어를 우선 사용하면, 제품 및 QA 팀과의 소통 효율성이 향상됩니다:

describe('InventoryAllocator', function () {
    it('reserves stock upon order placement')
        ->given(orderWithItems(['SKU-101' => 2]))
        ->when(fn() => allocate($order))
        ->then(fn() => expect(Stock::find('SKU-101')->reserved)->toBe(2));

    it('releases reserved stock on order cancellation')
        ->given(reservedOrder())
        ->when(fn() => cancel($order))
        ->then(fn() => expect(Stock::find('SKU-101')->reserved)->toBe(0));
});

피해야 할 명명 패턴

문제 있는 이름왜 문제인가개선된 이름
testUserCreation행동과 조건 부재it('creates user account with verified email')
testApiV2버전 정보만으로 의미 불명describe('API v2 endpoints') + 구체적 it() 케이스
testHappyPath모호한 용어, 재현 불가능it('processes valid checkout request')

자동화된 품질 보장

pest-plugin-test-naming을 설치해 정적 분석을 활성화하면, 다음과 같은 규칙을 강제할 수 있습니다:

  • 최소 길이 12자 이상
  • "it" 또는 "test"로 시작하며, "should", "can", "will" 등 모달 동사는 제외
  • 숫자나 약어 포함 금지 (예: testUppercaseit('converts string to uppercase'))

실무 체크리스트

  • 이름을 읽고 "어떤 상황에서 어떤 결과가 발생해야 하는가?"를 바로 대답할 수 있나요?
  • 클래스나 메서드 이름이 아닌, 사용자 관점의 행동에 초점을 두고 있나요?
  • describe() 계층이 실제 서비스/도메인 구조와 일치하나요?
  • 파라미터 테스트의 경우, 각 케이스가 어떤 비즈니스 조건을 반영하는지 명시되었나요?
  • 팀 내 모든 테스트가 동사 중심, 조건 명시, 중복 없이 작성되어 있나요?

태그: pest PHP bdd testing naming-convention

8월 21일 15:34에 게시됨