☰ 분류

테스트용 데이터 세트 설계하는 프롬프트

정상 케이스만이 아니라 깨지는 데이터를 같이 만듭니다. 실제 데이터를 복사하지 않게 합니다.

분류개발 › 데이터·DB
태그초안작성코드개발자
프롬프트 (영어 본문 · 답은 한국어로 옵니다)
Design a test data set for this schema.

Produce four groups:
1. **Typical** — a few rows that represent normal use.
2. **Boundary** — empty string versus null, zero, negative, maximum length, first and last day of a period, exactly at a limit and one past it.
3. **Messy** — the shapes real data actually takes: duplicate-looking names, mixed encodings, trailing whitespace, out-of-order timestamps, orphaned references where the constraint allows it.
4. **Should be rejected** — data that must fail validation, with which rule rejects it. *A test set with nothing that fails is only testing the happy path.*

For each row, say which scenario it exercises. Rows serving no scenario get cut.

Then:
- Relationships the fixtures must maintain, and the insert order.
- What cannot be tested with fixtures alone and needs a different approach — concurrency, volume, external services.
- ⚠️ **If I am considering copying production data**: name what must be removed or masked, and note that partial masking of real data is a common source of incidents. Synthetic data that reproduces the shape is usually safer.

Rules:
- Do not generate volume for its own sake. Ten deliberate rows beat ten thousand random ones.
- Use realistic but clearly fictional values — no real names, emails, or identifiers.
붙여 넣으면 맨 아래에 채울 칸(스키마 · 테스트할 시나리오 · 제약·규칙)이 나옵니다

어떤 프롬프트인가

테스트 데이터가 전부 예쁘면 테스트가 통과해도 의미가 없다. 이 프롬프트는 경계값과 지저분한 데이터를 같이 설계하고, 운영 데이터를 그대로 쓰면 안 되는 이유를 짚는다.

모델 비교

ChatGPT는 범위가 가장 넓지만 오류가 있고, Gemini는 시나리오가 더 정밀하나 누락과 가정이 있다. [C]는 답이 없다.

ChatGPT
41/ 50

+ 거부 규칙과 운영 데이터 위험을 폭넓게 다뤘다.

- 20자 코드가 실제로 14자이며 일부 시나리오 행이 없다.

Gemini
41/ 50

+ 고정 기준 시각으로 핵심 7개 시나리오를 구체화했다.

- 없는 users 열을 가정했고 일부 필수 경계를 빠뜨렸다.

기준ChatGPTGemini앞선 모델
지시 준수88동점
정확성78Gemini +14%
구체성99동점
구성·가독성99동점
분량 적정성87ChatGPT +14%

gpt-5.6-sol가 모델 이름을 가린 채 1~10점으로 채점했습니다 (2026-09-25). 측정값이 아니라 AI 심사 결과입니다.

답 전문 보기

같은 입력을 세 모델에 넣어 받은 답을 그대로 옮겼습니다. 각 CLI(에이전트 하네스)에서 실행했습니다. ChatGPT·Claude 앱이나 웹에서는 답이 다를 수 있습니다.

넣은 입력
스키마: CREATE TABLE coupons (
  id BIGSERIAL PRIMARY KEY,
  code VARCHAR(20) UNIQUE NOT NULL,
  discount_type VARCHAR(10) NOT NULL CHECK (discount_type IN ('PERCENT','FIXED')),
  discount_value NUMERIC(10,2) NOT NULL CHECK (discount_value > 0),
  min_order_amount NUMERIC(10,2) DEFAULT 0,
  starts_at TIMESTAMP NOT NULL,
  ends_at TIMESTAMP NOT NULL,
  max_uses INT,
  used_count INT NOT NULL DEFAULT 0,
  user_id BIGINT REFERENCES users(id),
  created_at TIMESTAMP NOT NULL DEFAULT now()
);

테스트할 시나리오: 1. 신규가입 웰컴 쿠폰 발급 및 정상 사용
2. 만료된 쿠폰(ends_at 지남)으로 결제 시도
3. 아직 시작 전(starts_at 미도달)인 쿠폰 사용 시도
4. 최소주문금액(min_order_amount) 미달 주문에 쿠폰 적용
5. max_uses 도달 후 추가 사용 시도(used_count = max_uses)
6. 퍼센트 할인(PERCENT)과 정액 할인(FIXED)이 같은 주문에 동시 적용되는 경우
7. 특정 유저 전용 쿠폰(user_id 지정)을 다른 유저가 사용 시도

제약·규칙: - discount_value는 0보다 커야 함
- discount_type='PERCENT'일 때 discount_value는 1~100 사이여야 함(앱 레벨 검증, DB CHECK는 없음)
- ends_at은 starts_at보다 뒤여야 함
- used_count는 max_uses를 초과할 수 없음
- code는 대문자 영숫자 6~20자, 공백 불가
- user_id가 NULL이면 전체 유저 대상 쿠폰
gpt-5.6-luna (codex CLI · 에이전트 하네스) · 실행일 2026-09-24

아래 값은 모두 허구이며, 날짜는 테스트 재현을 위해 고정했습니다. id와 created_at은 생략하면 DB 기본값을 사용합니다.

1. Typical

fixture code type value min_order starts_at ends_at max_uses used_count user_id 시나리오
T01 WELCOME26 PERCENT 10.00 0.00 2026-09-01 00:00:00 2026-12-31 23:59:59 1 0 1001 신규가입 웰컴 쿠폰 발급 및 정상 사용
T02 SHIPFREE26 FIXED 5.00 30.00 2026-09-01 00:00:00 2026-12-31 23:59:59 NULL 0 NULL 전체 유저 대상, 최소주문금액 충족
T03 VIP1002 PERCENT 20.00 50.00 2026-09-01 00:00:00 2026-10-31 23:59:59 3 1 1002 특정 유저 전용 쿠폰

NULL max_uses는 무제한 사용을 의미하는 애플리케이션 규칙이 필요합니다.

2. Boundary

fixture code type value min_order starts_at ends_at max_uses used_count user_id 시나리오 / 경계
B01 GENERALNULL FIXED 0.01 NULL 2026-09-01 00:00:00 2026-09-01 23:59:59 NULL 0 NULL min_order_amount = NULL, 전체 대상
B02 PERCENT100 PERCENT 100.00 0.00 2026-09-01 00:00:00 2026-09-30 23:59:59 100 100 NULL 퍼센트 할인 최대값, used_count = max_uses
B03 FIXEDMAX FIXED 99999999.99 0.00 2026-01-01 00:00:00 2026-12-31 23:59:59 1 0 NULL NUMERIC(10,2) 최대 유효값
B04 CODEMAX20CHARS FIXED 1.00 0.00 2026-09-01 00:00:00 2026-09-30 23:59:59 1 0 NULL code 길이 정확히 20자
B05 FIRSTDAY PERCENT 1.00 0.00 2026-09-01 00:00:00 2026-09-01 23:59:59 1 0 NULL 기간의 첫날
B06 LASTDAY PERCENT 1.00 0.00 2026-09-30 00:00:00 2026-09-30 23:59:59 1 0 NULL 기간의 마지막 날
B07 EXACTLIMIT PERCENT 100.00 100.00 2026-09-01 00:00:00 2026-09-02 00:00:00 1 0 NULL 할인율·최소주문금액 제한에 정확히 도달
B08 USEDLIMIT FIXED 10.00 0.00 2026-09-01 00:00:00 2026-09-02 00:00:00 2 2 NULL max uses 도달 후 추가 사용 시도

추가로 다음 경계값은 거부 데이터로 둡니다.

  • discount_value = 0, -0.01
  • 퍼센트 discount_value = 100.01
  • code 길이 21자
  • discount_value = 100000000.00 — NUMERIC(10,2) 범위 초과
  • used_count = max_uses + 1

3. Messy

fixture code type value min_order starts_at ends_at max_uses used_count user_id 시나리오 / 의도
M01 WELCOME0 PERCENT 10.00 0.00 2026-09-01 00:00:00 2026-12-31 23:59:59 1 0 NULL WELCOME O와 혼동하기 쉬운 유사 코드
M02 WELCOMEO PERCENT 10.00 0.00 2026-09-01 00:00:00 2026-12-31 23:59:59 1 0 NULL M01과 시각적으로 유사하지만 다른 코드
M03 BACKDATE1 FIXED 3.50 10.00 2026-10-01 00:00:00 2026-10-31 23:59:59 NULL 0 1002 created_at이 starts_at보다 늦거나 이른 데이터 처리 검증
M04 NULLMIN01 FIXED 2.00 NULL 2026-09-01 00:00:00 2026-09-30 23:59:59 NULL 0 1001 명시적 NULL과 DEFAULT 0 구분
M05 MIXEDCASE FIXED 7.25 20.00 2026-09-05 12:00:00 2026-09-04 12:00:00 NULL 0 NULL 날짜가 역순인 입력. 앱 검증에서 거부되어야 함

M05는 DB CHECK가 없으므로 DB에는 들어갈 수 있지만 앱 규칙상 거부해야 합니다.

이 테이블에는 이름이나 자유 텍스트가 없으므로 “중복-looking 이름”과 “혼합 인코딩”은 직접 재현할 필드가 없습니다. 코드의 ASCII 대문자·숫자 규칙 때문에 유니코드 유사문자나 공백 코드는 별도의 거부 데이터로 테스트해야 합니다.

4. Should be rejected

fixture 입력 예 거부 규칙
R01 code = '' code는 6~20자여야 함
R02 code = 'ABC12 ' 공백 불가
R03 code = 'abc123' 대문자 영숫자만 허용
R04 code = 'ABCDE' code 최소 길이 6자
R05 code = 'ABCDEFGHIJKLMNOPQRSTU' code 최대 길이 20자 초과
R06 code = NULL NOT NULL
R07 discount_type = 'PERCENT', discount_value = 0 DB CHECK: discount_value > 0
R08 discount_type = 'FIXED', discount_value = -1.00 DB CHECK: discount_value > 0
R09 discount_type = 'PERCENT', discount_value = 100.01 앱 규칙: PERCENT는 1~100
R10 discount_type = 'PERCENT', discount_value = 0.99 앱 규칙: PERCENT 최소 1
R11 discount_type = 'UNKNOWN' DB CHECK의 허용 타입 위반
R12 starts_at = '2026-09-10', ends_at = '2026-09-10' 앱 규칙: ends_at > starts_at
R13 starts_at = '2026-09-11', ends_at = '2026-09-10' 앱 규칙: 기간 역전
R14 max_uses = 2, used_count = 3 앱 규칙: used_count <= max_uses
R15 user_id = 999999999 존재하지 않는 users.id에 대한 FK 위반
R16 discount_value = 100000000.00 NUMERIC(10,2) 범위 초과

관계와 삽입 순서

  1. 먼저 users에 테스트 사용자 삽입

    • 1001: 가상의 신규 사용자
    • 1002: 가상의 VIP 사용자
    • 1003: 쿠폰 소유자가 아닌 다른 사용자
  2. coupons 삽입

    • user_id = NULL: 모든 사용자 대상
    • user_id = 1002: 해당 사용자 전용
    • 특정 사용자 쿠폰 테스트 시 1003으로 사용 시도
  3. 실제 시나리오 검증용 orders와 coupon_applications 같은 테이블 또는 테스트 객체 생성

  4. 주문과 쿠폰 적용을 삽입

    • 최소주문금액 미달 주문
    • 만료 시각 이후 주문
    • 시작 시각 이전 주문
    • PERCENT와 FIXED를 같은 주문에 적용
    • used_count = max_uses 상태에서 추가 적용

현재 스키마에는 주문, 쿠폰 적용 이력, 사용한 사용자 정보가 없으므로 used_count만으로 누가 언제 사용했는지는 추적할 수 없습니다.

Fixtures만으로 테스트할 수 없는 것

  • 동일 쿠폰을 동시에 사용하는 경쟁 조건
  • used_count 증가의 원자성 및 초과 사용 방지
  • 대량 쿠폰·대량 사용자에서의 성능과 인덱스 효율
  • 결제 서비스, 회원 서비스, 메시지 발송 등 외부 서비스 장애
  • 트랜잭션 롤백과 재시도
  • 실제 시간대·서버 시간 차이
  • 퍼센트와 정액 쿠폰의 중복 적용 정책

이 항목들은 동시성 테스트, 부하 테스트, 시간 주입(clock mocking), 외부 서비스 mock 또는 통합 테스트가 필요합니다.

운영 데이터 복사 시 주의

운영 데이터를 복사한다면 다음을 제거하거나 마스킹해야 합니다.

  • 사용자 이름, 이메일, 전화번호, 주소
  • users.id와 연결 가능한 실제 식별자
  • 쿠폰 코드, 주문번호, 결제 식별자
  • 인증 토큰, API 키, 내부 메모
  • 실제 금액·구매 패턴·사용 시각처럼 재식별에 사용될 수 있는 정보

부분적으로만 마스킹한 운영 데이터는 다른 테이블의 원본 값, 코드 형식, 시간 패턴과 결합되어 개인정보나 비밀이 노출되는 사고로 이어질 수 있습니다. 이 경우에는 운영 데이터 복사보다 동일한 분포와 예외 형태를 재현하는 합성 데이터를 생성하는 편이 안전합니다.

같은 분류의 프롬프트

대용량 텍스트 변환기 프롬프트
AI 데이터 추출 도구 기획 프롬프트
AI2sql 자연어 SQL 생성 프롬프트
백엔드 아키텍트 역할을 맡기는 프롬프트
Base R 프로그래밍 프롬프트