[프롬프트] 함수 단위 테스트 코드 자동 작성 프롬프트 - 최적 프롬프트 레시피
💡 한 줄 요약: "이 함수 테스트 코드 짜줘"라는 단순 요청 시 발생하는 Happy Path 전용 껍데기 테스트를 완전히 종결하고, Staff QA Architect 관점에서 경계값 분석(BVA), 동시성 경합, 시간 왜곡(Fake Timers), 외부 I/O Mock 격리, 멱등성 검증까지 완벽하게 커버하는 고밀도 단위 테스트 생성 프롬프트 레시피입니다.
1. 페인포인트 & 작업 목표
expect(result).toBe(true) 식의 얕은 검증을 수행하여, null/undefined/오버플로/경계값 조건에서 발생하는 런타임 크래시를 방어하지 못함.sleep()으로 대기하여 CI 파이프라인 지연을 유발하거나 타이밍 플래키(Flaky) 테스트를 양산함.2. 프롬프트 레시피 비교
❌ 레시피 A: 기본형 (단순 질의 초안)
프레임워크나 경계 조건, Mock 요구사항 없이 테스트 생성을 단순 요청하는 초안입니다.
[영문 프롬프트 (복사용)]
Write unit tests for this function:
[PASTE_FUNCTION_CODE_HERE][한글 프롬프트 (1:1 매칭 복사용)]
이 함수에 대한 단위 테스트 코드를 작성해줘:
[여기에_함수_코드_붙여넣기]⚡ 레시피 B: Staff QA Architect 실무 종결형 단위 테스트 프롬프트
순수 비즈니스 로직, 상태 머신, 알고리즘, 타이머 의존 함수를 위해 경계값 분석(BVA)과 동시성/시간 왜곡 검증을 체계화하는 종합 레시피입니다.
[영문 프롬프트 (복사용)]
You are a Staff QA Architect and Principal Software Engineer in Test (SDET) specializing in robust test automation frameworks and formal boundary value analysis.
Generate production-grade, battle-tested unit test suites for the provided function adhering strictly to the AAA (Arrange-Act-Assert) pattern.
### Target Environment & Framework:
- Test Runner & Assertion Library: [e.g., Vitest / Jest / Pytest / Go testing]
- Mocking & Fake Timer Strategy: Modern native mocking (e.g., vi.useFakeTimers(), jest.spyOn())
- Source Function Under Test:
[PASTE_SOURCE_FUNCTION_HERE]
### Test Generation Requirements:
1. TEST MATRIX DESIGN: Categorize Happy Paths, Boundary Conditions, Invalid Inputs, and Timing Edge Cases.
2. STRICT AAA PATTERN: Structure every test with distinct // Arrange, // Act, // Assert sections.
3. EXTREME BOUNDARY COVERAGE: Test min, max, zero, negative, off-by-one, overflow, and empty collections.
4. DETERMINISTIC TIMING: Use virtual fake timers to advance time instantly without real-time sleep.
5. EXHAUSTIVE ASSERTIONS: Assert returned values, state transitions, thrown error types, and messages.[한글 프롬프트 (1:1 매칭 복사용)]
당신은 견고한 테스트 자동화 프레임워크와 정밀 경계값 분석(BVA)을 전문으로 하는 스태프 QA 아키텍트(Staff QA Architect)이자 수석 테스트 엔지니어(SDET)입니다.
제공된 대상 함수에 대해 AAA(Arrange-Act-Assert) 패턴을 엄격히 준수하여 프로덕션급의 철저한 단위 테스트 스위트를 작성하십시오.
### 대상 환경 및 프레임워크:
- 테스트 러너 및 단언 라이브러리: [예: Vitest / Jest / Pytest / Go testing]
- 모킹 및 가짜 타이머 전략: 모던 네이티브 모킹 (예: vi.useFakeTimers(), jest.spyOn())
- 테스트 대상 소스 함수:
[여기에_대상_함수_코드_붙여넣기]
### 테스트 생성 요구사항:
1. 테스트 케이스 매트릭스 도출: 해피 패스, 경계 조건, 유효하지 않은 입력, 동시성/타이밍 엣지 케이스 분류.
2. 엄격한 AAA 패턴: 모든 테스트를 // Arrange, // Act, // Assert 주석 구역으로 명확히 구분.
3. 극한의 경계값 커버리지: 최솟값, 최댓값, 0, 음수, 오프바이원(Off-by-one), 오버플로, 빈 컬렉션 검증.
4. 결정론적 타이밍 제어: 가짜 타이머(Fake Timers)로 실제 대기 없이 시간 조작.
5. 다각적 단언: 반환값, 상태 전이, 발생 예외 타입 및 에러 메시지 일치 여부 단언.setTimeout이나 타임스탬프를 다루는 함수에서 실제 sleep을 배제하고 가상 시계를 전진시켜 테스트 속도와 안정성을 동시에 확보합니다.🚀 레시피 C: 비동기 I/O 및 외부 API Mock 격리 특화 (I/O Isolation Tester)
데이터베이스 쿼리, 결제 게이트웨이, 서드파티 웹훅, HTTP 통신이 포함된 비동기 함수에 대해 완벽한 테스트 격리와 실패 복원력을 검증하는 레시피입니다.
[영문 프롬프트 (복사용)]
You are a Principal Test Automation Engineer specializing in distributed system test harnesses, contract testing, and asynchronous I/O isolation.
Generate fully isolated, resilient unit tests for the provided asynchronous function that interacts with external dependencies (APIs, DBs, Webhooks).
### Target Specifications:
- Language & Test Framework: [e.g., Python Pytest (pytest-mock, pytest-asyncio) / TypeScript Vitest]
- External Dependencies to Isolate: [e.g., Stripe API Client, Redis Cache, Database Session]
- Source Code Under Test:
[PASTE_ASYNC_FUNCTION_HERE]
### Test Generation Directives:
1. STRICT MOCK ISOLATION & ZERO EXTERNAL LEAK:
- Mock all network, database, and message broker interactions using standard spied mocks.
- Never allow real network sockets or I/O calls to escape the test process.
2. FAILURE INJECTION & RESILIENCY SCENARIOS:
- Test network socket timeouts, 5xx internal server errors, malformed payloads, rate-limit (429) responses, and invalid cryptographic signatures.
3. IDEMPOTENCY & DUPLICATE CALL VERIFICATION:
- Verify that duplicate calls with the same transaction key do not trigger duplicate side effects.
4. SPY CALL VERIFICATION:
- Assert exact mock call counts, parameter payloads, and verify that rollbacks are invoked on failure.[한글 프롬프트 (1:1 매칭 복사용)]
당신은 분산 시스템 테스트 하네스, 계약 테스팅, 비동기 I/O 격리를 전문으로 하는 수석 테스트 자동화 엔지니어(Principal SDET)입니다.
외부 의존성(API, DB, 웹훅 등)과 통신하는 비동기 함수에 대해 완벽히 격리되고 복원력 높은 단위 테스트 스위트를 생성하십시오.
### 대상 사양:
- 언어 및 테스트 프레임워크: [예: Python Pytest (pytest-mock, pytest-asyncio) / TypeScript Vitest]
- 격리 대상 외부 의존성: [예: Stripe API 클라이언트, Redis 캐시, DB 세션]
- 테스트 대상 소스 코드:
[여기에_비동기_함수_붙여넣기]
### 테스트 생성 지침:
1. 완벽한 Mock 격리 및 외부 누출 원천 차단:
- 모든 네트워크, 데이터베이스, 메시지 브로커 인터페이스를 스파이 Mock으로 격리하십시오.
- 실제 네트워크 소켓이나 I/O 호출이 테스트 환경 외부로 누출되지 않도록 하십시오.
2. 장애 주입(Failure Injection) 및 복원력 검증:
- 소켓 타임아웃, 5xx 서버 장애, 기형적 페이로드, Rate Limit(429), 위조된 암호학적 서명 시나리오를 검증하십시오.
3. 멱등성 및 중복 호출 방어 검증:
- 동일한 트랜잭션 키로 중복 요청이 유입될 때 부수 효과(이중 청구 등)가 발생하지 않는지 검증하십시오.
- 롤백 호출 여부 및 Mock 호출 횟수/파라미터를 엄격하게 단언하십시오.mock.assert_called_once_with() 및 DB 롤백 호출 여부를 추적해 시스템 무결성을 검증합니다.3. 실행 결과 비교: 레시피 A vs B vs C 실전 대조
❌ 레시피 A 실행 결과: [단순 질의의 한계] 껍데기뿐인 단일 Happy Path 테스트
토큰 버킷 알고리즘 기반 Rate Limiter 함수를 레시피 A에 입력했을 때의 결과입니다.
// ❌ AI의 단순 답변: 엣지 케이스와 시간 제어가 결여된 표면적 테스트
describe('consumeToken', () => {
it('토큰을 정상적으로 소비해야 한다', () => {
const limiter = new TokenBucketLimiter({ capacity: 10, refillRate: 1 });
const result = limiter.consume('user-1', 1);
expect(result).toBe(true);
});
});⚡ 레시피 B 실행 결과: [실전 사례 1] 토큰 버킷 Rate Limiter 함수의 Vitest 단위 테스트
1차 소스 코드 주입
유저별 토큰 버킷 생성, 시간 경과 기반 누적 보충, 동시 요청 소비를 처리하는 TypeScript 클래스 함수.
AI 생성 출력 결과 (핵심 발췌)
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { TokenBucketLimiter } from './token-bucket-limiter';
describe('TokenBucketLimiter Unit Tests (Deterministic Timing)', () => {
let limiter: TokenBucketLimiter;
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-01-01T00:00:00.000Z'));
limiter = new TokenBucketLimiter({ capacity: 5, refillRatePerSec: 1 });
});
afterEach(() => { vi.useRealTimers(); });
// 1. Happy Path & Initial Capacity
it('버킷 생성 직후 용량 한도 내의 정상 토큰 소비를 허용해야 한다', () => {
// Arrange & Act
const allowed = limiter.consume('usr_test_100', 3);
// Assert
expect(allowed).toBe(true);
expect(limiter.getRemainingTokens('usr_test_100')).toBe(2);
});
// 2. Boundary Value Analysis: Exhaustion & Rejection
it('잔여 토큰보다 많은 요청이 들어오면 정확히 거절하고 잔여량을 유지해야 한다', () => {
// Arrange: 5개 모두 소진 후 1개 추가 시도 (경계값 0 상태)
limiter.consume('usr_test_101', 5);
// Act & Assert
expect(limiter.consume('usr_test_101', 1)).toBe(false);
expect(limiter.getRemainingTokens('usr_test_101')).toBe(0);
});
// 3. Virtual Time Advance: Refill Logic
it('가짜 타이머 전진 시 설정된 비율에 맞춰 토큰이 정확히 재충전되어야 한다', () => {
// Arrange: 5개 소진 후 3.5초 전진 (초당 1개 충전 -> 3개 충전)
limiter.consume('usr_test_102', 5);
// Act
vi.advanceTimersByTime(3500);
// Assert
expect(limiter.getRemainingTokens('usr_test_102')).toBe(3);
expect(limiter.consume('usr_test_102', 2)).toBe(true);
expect(limiter.getRemainingTokens('usr_test_102')).toBe(1);
});
// 4. Boundary Value: Capacity Overflow Prevention
it('오랜 시간이 흘러도 최대 버킷 용량을 초과하여 누적 충전되지 않아야 한다', () => {
// Act: 1시간(3600초) 전진 -> Assert: 최대 5개로 제한
vi.advanceTimersByTime(3600 * 1000);
expect(limiter.getRemainingTokens('usr_test_103')).toBe(5);
});
// 5. Invalid Input & Defensive Guard
it('요청 토큰이 0 이하이거나 용량보다 큰 경우 예외를 발생시켜야 한다', () => {
expect(() => limiter.consume('usr_test_104', 0)).toThrowError(/Invalid token amount/);
expect(() => limiter.consume('usr_test_104', -1)).toThrowError(/Invalid token amount/);
expect(() => limiter.consume('usr_test_104', 10)).toThrowError(/Requested tokens exceed capacity/);
});
});후속 체이닝 2종
> 추가 프롬프트: "Promise.all()을 사용해 동일 유저로부터 동시에 10개의 비동기 토큰 소비 요청이 도착할 때, 정확히 앞선 5개만 허용되고 나머지 5개는 거절되는 원자적(Atomic) 동시성 테스트를 추가해줘."
> 추가 프롬프트: "오랫동안 비활성 상태인 유저의 버킷 객체가 메모리에 영구 보존되지 않고 TTL(1시간) 후 메모리에서 청소되는지 검증하는 단위 테스트를 작성해줘."
4단계 워크플로우
vi.useFakeTimers()를 통해 $0$ 밀리초 단위로 수 시간의 시간 경과를 결정론적으로 시뮬레이션.🚀 레시피 C 실행 결과: [실전 사례 2] Stripe 결제 웹훅 비동기 핸들러 함수의 Pytest/Mock 격리 테스트
1차 소스 코드 주입
외부 Stripe 웹훅 서명 검증, 데이터베이스 멱등 주문 업데이트, 잔고 충전 이벤트를 비동기로 처리하는 Python 함수.
AI 생성 출력 결과 (핵심 발췌)
import pytest
from unittest.mock import AsyncMock, MagicMock
from app.services.webhook import handle_stripe_webhook
from app.exceptions import InvalidSignatureError, DuplicateEventError, PaymentGatewayTimeoutError
@pytest.fixture
def mock_stripe_verifier(mocker):
return mocker.patch("app.services.webhook.stripe.Webhook.construct_event")
@pytest.fixture
def mock_db_session():
session = AsyncMock()
session.commit, session.rollback = AsyncMock(), AsyncMock()
return session
@pytest.mark.asyncio
async def test_webhook_success_happy_path(mock_stripe_verifier, mock_db_session, mocker):
# Arrange: 유효한 결제 완료 이벤트 수신 설정
payload, signature = b'{"id": "evt_test_success"}', "valid_sig_header"
mock_stripe_verifier.return_value = {
"id": "evt_test_success", "type": "payment_intent.succeeded",
"data": {"object": {"id": "pi_123", "amount": 50000}}
}
mock_order = mocker.patch("app.services.webhook.OrderService.process_payment", new_callable=AsyncMock)
# Act
result = await handle_stripe_webhook(payload, signature, db=mock_db_session)
# Assert: 비즈니스 성공 반환 및 DB 커밋 확인
assert result == {"status": "processed", "event_id": "evt_test_success"}
mock_stripe_verifier.assert_called_once_with(payload, signature, "whsec_test_secret")
mock_order.assert_awaited_once_with("pi_123", 50000, db=mock_db_session)
mock_db_session.commit.assert_awaited_once()
mock_db_session.rollback.assert_not_called()
@pytest.mark.asyncio
async def test_webhook_invalid_signature_raises_400(mock_stripe_verifier, mock_db_session):
mock_stripe_verifier.side_effect = InvalidSignatureError("Signature mismatch")
with pytest.raises(InvalidSignatureError, match="Signature mismatch"):
await handle_stripe_webhook(b'tampered', "bad_sig", db=mock_db_session)
mock_db_session.commit.assert_not_called()
@pytest.mark.asyncio
async def test_webhook_duplicate_event_idempotency_guard(mock_stripe_verifier, mock_db_session, mocker):
# Arrange: 이미 처리된 동일 웹훅 수신 시 부수 효과 차단
mock_stripe_verifier.return_value = {"id": "evt_duplicate", "type": "payment_intent.succeeded"}
mocker.patch("app.services.webhook.EventLog.exists", new_callable=AsyncMock, return_value=True)
mock_order = mocker.patch("app.services.webhook.OrderService.process_payment", new_callable=AsyncMock)
# Act & Assert
result = await handle_stripe_webhook(b'payload', "sig", db=mock_db_session)
assert result == {"status": "skipped", "reason": "duplicate"}
mock_order.assert_not_awaited()
mock_db_session.commit.assert_not_called()
@pytest.mark.asyncio
async def test_webhook_db_failure_triggers_rollback(mock_stripe_verifier, mock_db_session, mocker):
mock_stripe_verifier.return_value = {"id": "evt_err", "data": {"object": {"id": "pi_1"}}}
mocker.patch("app.services.webhook.OrderService.process_payment", new_callable=AsyncMock, side_effect=Exception("DB Deadlock"))
with pytest.raises(Exception, match="DB Deadlock"):
await handle_stripe_webhook(b'payload', "sig", db=mock_db_session)
mock_db_session.rollback.assert_awaited_once()후속 체이닝: 네트워크 타임아웃 및 서킷 브레이커 연동 체이닝
PaymentGatewayTimeoutError(502/504)를 일으킬 때, 웹훅 함수가 이벤트를 즉시 실패 처리하지 않고 DLQ(Dead Letter Queue)로 전달한 뒤 500 에러를 던져 Stripe 측의 재전송을 유도하는 분기 테스트를 추가해줘."3단계 워크플로우
4. 견고한 단위 테스트 작성을 위한 4대 엔지니어링 원칙
sleep(1000)과 같은 실제 대기는 CI 파이프라인 지연과 간헐적 실패(Flaky)의 주범입니다. 타이머 모킹을 통해 가상 시간을 전진시키는 기법을 프롬프트로 강제해야 합니다.5. 실전 투입용 플레이스홀더 템플릿
실무에서 신규 구현 함수나 버그 수정 패치에 대한 테스트를 즉시 생성할 때 복사하여 사용하는 프롬프트 템플릿입니다.
[역할 정의]
당신은 완벽한 코드 커버리지와 엣지 케이스 방어에 능통한 Staff SDET이자 QA 아키텍트입니다.
[대상 환경 및 언어]
- 언어/버전: [예: TypeScript 5.4 / Python 3.12 / Java 21 / Go 1.22]
- 테스트 러너: [Vitest / Jest / Pytest / JUnit 5 / Testify]
- 모킹 라이브러리: [내장 모킹 모듈 / unittest.mock / Mockito]
[테스트 대상 함수 코드][여기에 테스트할 함수 코드를 붙여넣으십시오]
[테스트 생성 요구사항]
1. 해피 패스, 경계 조건(0, null, 음수, 오프바이원), 예외 입력, 비동기/동시성 케이스를 포괄하는 매트릭스를 먼저 나열할 것.
2. 모든 테스트는 // Arrange, // Act, // Assert 구조를 엄격히 지킬 것.
3. 외부 I/O 및 시간 지연 로직은 Fake Timers 및 스파이 Mock을 활용해 완전 격리할 것.
4. 실패 시나리오에서 트랜잭션 롤백, 에러 타입 및 메시지 일치 여부를 단언할 것.6. 프롬프트 활용 팁 & 주의사항
setTimeout에 의존하지 말고 이벤트 루프 틱 플러시(flushPromises()) 또는 프레임워크의 공식 Fake Timers API를 사용하는지 점검하십시오.>를 >=로)나 연산자를 슬쩍 변경했을 때 테스트가 반드시 실패(Kill)하는지 역검증하여 테스트의 진정성을 확보하십시오.