☰ Categories

Design a test data set

Builds the data that breaks things, not only the happy path, and keeps production data out of it.

CategoryDevelopment › Data & databases
TagsDraftingCodeDeveloper
Prompt
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.
After pasting, fill in the fields at the bottom (Schema · Scenarios · Constraints)

What this prompt does

If every fixture is clean, passing tests prove nothing. This designs boundary and messy cases alongside, and flags why copying production data is not the shortcut it looks like.

Model comparison

ChatGPT is broadest but contains errors; Gemini models scenarios more precisely but has omissions and assumptions. [C] is absent.

ChatGPT
41/ 50

+ Broad coverage of rejection rules and production-data risks.

- The claimed 20-character code has 14 characters, and some scenario rows are missing.

Gemini
41/ 50

+ Uses a fixed clock to make all seven scenarios concrete.

- It invents users columns and omits several required boundaries.

CriterionChatGPTGeminiLeader
Instruction following88Tie
Accuracy78Gemini +14%
Specificity99Tie
Structure99Tie
Right length87ChatGPT +14%

Scored 1–10 by gpt-5.6-sol with model names hidden (2026-09-25). This is an AI review, not a measurement.

Read full answers

We gave three models the same input and copied their answers unedited. Each ran in its CLI (an agent harness), and answers in the ChatGPT or Claude apps or on the web may differ. Outputs are in Korean.

Input used
Schema: 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()
);

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

Constraints: - 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 · 에이전트 하네스) · Run on 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 키, 내부 메모
  • 실제 금액·구매 패턴·사용 시각처럼 재식별에 사용될 수 있는 정보

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

More in this category

Advanced Text Converter for Large Datasets
AI-powered data extraction and organization tool
AI2sql SQL Model — Query Generator
Backend Architect
base-R