+ Broad coverage of rejection rules and production-data risks.
- The claimed 20-character code has 14 characters, and some scenario rows are missing.
Builds the data that breaks things, not only the happy path, and keeps production data out of it.
| Category | Development › Data & databases |
|---|---|
| Tags | DraftingCodeDeveloper |
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.
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.
ChatGPT is broadest but contains errors; Gemini models scenarios more precisely but has omissions and assumptions. [C] is absent.
+ Broad coverage of rejection rules and production-data risks.
- The claimed 20-character code has 14 characters, and some scenario rows are missing.
+ Uses a fixed clock to make all seven scenarios concrete.
- It invents users columns and omits several required boundaries.
| Criterion | ChatGPT | Gemini | Leader |
|---|---|---|---|
| Instruction following | 8 | 8 | Tie |
| Accuracy | 7 | 8 | Gemini +14% |
| Specificity | 9 | 9 | Tie |
| Structure | 9 | 9 | Tie |
| Right length | 8 | 7 | ChatGPT +14% |
Scored 1–10 by gpt-5.6-sol with model names hidden (2026-09-25). This is an AI review, not a measurement.
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.
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이면 전체 유저 대상 쿠폰아래 값은 모두 허구이며, 날짜는 테스트 재현을 위해 고정했습니다. id와 created_at은 생략하면 DB 기본값을 사용합니다.
| 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는 무제한 사용을 의미하는 애플리케이션 규칙이 필요합니다.
| 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.01discount_value = 100.01code 길이 21자discount_value = 100000000.00 — NUMERIC(10,2) 범위 초과used_count = max_uses + 1| 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 대문자·숫자 규칙 때문에 유니코드 유사문자나 공백 코드는 별도의 거부 데이터로 테스트해야 합니다.
| 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) 범위 초과 |
먼저 users에 테스트 사용자 삽입
1001: 가상의 신규 사용자1002: 가상의 VIP 사용자1003: 쿠폰 소유자가 아닌 다른 사용자coupons 삽입
user_id = NULL: 모든 사용자 대상user_id = 1002: 해당 사용자 전용1003으로 사용 시도실제 시나리오 검증용 orders와 coupon_applications 같은 테이블 또는 테스트 객체 생성
주문과 쿠폰 적용을 삽입
PERCENT와 FIXED를 같은 주문에 적용used_count = max_uses 상태에서 추가 적용현재 스키마에는 주문, 쿠폰 적용 이력, 사용한 사용자 정보가 없으므로 used_count만으로 누가 언제 사용했는지는 추적할 수 없습니다.
used_count 증가의 원자성 및 초과 사용 방지이 항목들은 동시성 테스트, 부하 테스트, 시간 주입(clock mocking), 외부 서비스 mock 또는 통합 테스트가 필요합니다.
운영 데이터를 복사한다면 다음을 제거하거나 마스킹해야 합니다.
users.id와 연결 가능한 실제 식별자부분적으로만 마스킹한 운영 데이터는 다른 테이블의 원본 값, 코드 형식, 시간 패턴과 결합되어 개인정보나 비밀이 노출되는 사고로 이어질 수 있습니다. 이 경우에는 운영 데이터 복사보다 동일한 분포와 예외 형태를 재현하는 합성 데이터를 생성하는 편이 안전합니다.
| Advanced Text Converter for Large Datasets | |
| AI-powered data extraction and organization tool | |
| AI2sql SQL Model — Query Generator | |
| Backend Architect | |
| base-R |