Communitygithub.com

AI 회귀 테스트

AI 기반 개발을 위한 회귀 테스트 전략. 데이터베이스 의존성 없는 샌드박스 모드 API 테스트, 자동화된 버그 검사 워크플로우, 그리고 동일한 모델이 코드를 작성하고 리뷰할 때 발생하는 AI 사각지대를 포착하는 패턴을 제공합니다. AI 지원 코드에 회귀 테스트를 추가하거나, 동일한 모델이 변경 사항을 작성하고 리뷰한 경우에 사용하세요.

AI 회귀 테스트란 무엇인가요?

AI 회귀 테스트는 동일한 AI 모델이 코드를 작성하고 리뷰할 때 발생하는 체계적인 사각지대를 자동화된 테스트로 포착하기 위한 전략입니다. Claude Code, Cursor, Codex 등 AI 기반 개발 환경에서 특히 유용하며, 샌드박스/프로덕션 경로 불일치, SELECT 절 누락, 오류 상태 누출, 낙관적 업데이트 롤백 누락 등 AI가 자주 범하는 회귀 패턴을 집중적으로 테스트합니다. Vitest와 Next.js App Router 환경에서 데이터베이스 없이도 API 라우트를 테스트할 수 있는 샌드박스 모드 설정과 헬퍼 함수를 제공하며, 실제 버그가 발견된 위치에만 테스트를 작성하는 실용적인 접근법을 따릅니다. 또한 `/bug-check` 명령어를 통해 테스트 실행, 빌드 검증, 코드 리뷰, 회귀 테스트 작성을 자동화하는 워크플로우를 지원합니다.

지원 대상✓Claude Code✓Codex CLI✓Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/ai-regression-testing

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

AI 회귀 테스트은(는) 무엇을 하나요?

동일한 모델이 코드를 작성하고 리뷰하는 AI 기반 개발 환경을 위해 특별히 설계된 테스트 패턴입니다. 이러한 환경에서는 자동화된 테스트만이 잡아낼 수 있는 체계적인 사각지대가 발생합니다.

활성화 시점

  • AI 에이전트(Claude Code, Cursor, Codex)가 API 라우트나 백엔드 로직을 수정한 경우
  • 버그를 발견하고 수정한 경우 — 재발 방지 필요
  • 프로젝트에 DB 없이 테스트할 수 있는 샌드박스/모의 모드가 있는 경우
  • 코드 변경 후 /bug-check 또는 유사한 리뷰 명령어를 실행하는 경우
  • 여러 코드 경로가 존재하는 경우 (샌드박스 vs 프로덕션, 기능 플래그 등)

핵심 문제

AI가 코드를 작성하고 자신의 작업을 리뷰할 때, 두 단계 모두에서 동일한 가정을 유지합니다. 이로 인해 예측 가능한 실패 패턴이 발생합니다:

AI가 수정 작성 → AI가 수정 리뷰 → AI가 "올바름" 판단 → 버그 여전히 존재

실제 사례 (프로덕션에서 관찰됨):

수정 1: API 응답에 notification_settings 추가
  → SELECT 쿼리에 추가하는 것을 잊음
  → AI가 리뷰했지만 놓침 (동일한 사각지대)

수정 2: SELECT 쿼리에 추가
  → TypeScript 빌드 오류 (생성된 타입에 컬럼 없음)
  → AI가 수정 1을 리뷰했지만 SELECT 문제를 잡지 못함

수정 3: SELECT * 로 변경
  → 프로덕션 경로 수정, 샌드박스 경로 누락
  → AI가 다시 리뷰했지만 또 놓침 (4번째 발생)

수정 4: 테스트가 첫 실행에 즉시 발견 - 통과:

패턴: 샌드박스/프로덕션 경로 불일치는 AI가 유발하는 1위 회귀 유형입니다.

샌드박스 모드 API 테스트

AI 친화적인 아키텍처를 가진 대부분의 프로젝트에는 샌드박스/모의 모드가 있습니다. 이것이 빠르고 DB 없는 API 테스트의 핵심입니다.

설정 (Vitest + Next.js App Router)

// vitest.config.ts
import { defineConfig } from "vitest/config";
import path from "path";

export default defineConfig({
  test: {
    environment: "node",
    globals: true,
    include: ["__tests__/**/*.test.ts"],
    setupFiles: ["__tests__/setup.ts"],
  },
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "."),
    },
  },
});
// __tests__/setup.ts
// 샌드박스 모드 강제 — 데이터베이스 불필요
process.env.SANDBOX_MODE = "true";
process.env.NEXT_PUBLIC_SUPABASE_URL = "";
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY = "";

Next.js API 라우트 테스트 헬퍼

// __tests__/helpers.ts
import { NextRequest } from "next/server";

export function createTestRequest(
  url: string,
  options?: {
    method?: string;
    body?: Record<string, unknown>;
    headers?: Record<string, string>;
    sandboxUserId?: string;
  },
): NextRequest {
  const { method = "GET", body, headers = {}, sandboxUserId } = options || {};
  const fullUrl = url.startsWith("http") ? url : `http://localhost:3000${url}`;
  const reqHeaders: Record<string, string> = { ...headers };

  if (sandboxUserId) {
    reqHeaders["x-sandbox-user-id"] = sandboxUserId;
  }

  const init: { method: string; headers: Record<string, string>; body?: string } = {
    method,
    headers: reqHeaders,
  };

  if (body) {
    init.body = JSON.stringify(body);
    reqHeaders["content-type"] = "application/json";
  }

  return new NextRequest(fullUrl, init);
}

export async function parseResponse(response: Response) {
  const json = await response.json();
  return { status: response.status, json };
}

회귀 테스트 작성

핵심 원칙: 작동하는 코드가 아니라 발견된 버그에 대한 테스트를 작성하세요.

// __tests__/api/user/profile.test.ts
import { describe, it, expect } from "vitest";
import { createTestRequest, parseResponse } from "../../helpers";
import { GET, PATCH } from "@/app/api/user/profile/route";

// 응답에 반드시 포함되어야 하는 필드 정의
const REQUIRED_FIELDS = [
  "id",
  "email",
  "full_name",
  "phone",
  "role",
  "created_at",
  "avatar_url",
  "notification_settings",  // ← 버그 발견 후 추가됨
];

describe("GET /api/user/profile", () => {
  it("모든 필수 필드를 반환한다", async () => {
    const req = createTestRequest("/api/user/profile");
    const res = await GET(req);
    const { status, json } = await parseResponse(res);

    expect(status).toBe(200);
    for (const field of REQUIRED_FIELDS) {
      expect(json.data).toHaveProperty(field);
    }
  });

  // 회귀 테스트 — 이 특정 버그는 AI에 의해 4번 유발됨
  it("notification_settings가 undefined가 아니다 (BUG-R1 회귀)", async () => {
    const req = createTestRequest("/api/user/profile");
    const res = await GET(req);
    const { json } = await parseResponse(res);

    expect("notification_settings" in json.data).toBe(true);
    const ns = json.data.notification_settings;
    expect(ns === null || typeof ns === "object").toBe(true);
  });
});

샌드박스/프로덕션 일관성 테스트

가장 흔한 AI 회귀: 프로덕션 경로를 수정했지만 샌드박스 경로를 잊는 경우(또는 그 반대).

// 샌드박스 응답이 예상된 계약을 준수하는지 테스트
describe("GET /api/user/messages (대화 목록)", () => {
  it("샌드박스 모드에서 partner_name을 포함한다", async () => {
    const req = createTestRequest("/api/user/messages", {
      sandboxUserId: "user-001",
    });
    const res = await GET(req);
    const { json } = await parseResponse(res);

    // 이 테스트는 partner_name이 프로덕션 경로에는 추가되었지만
    // 샌드박스 경로에는 추가되지 않은 버그를 잡았습니다.
    if (json.data.length > 0) {
      for (const conv of json.data) {
        expect("partner_name" in conv).toBe(true);
      }
    }
  });
});

버그 검사 워크플로우에 테스트 통합

사용자 정의 명령어 정의

<!-- .claude/commands/bug-check.md -->
# 버그 검사

## 1단계: 자동화된 테스트 (필수, 건너뛸 수 없음)

코드 리뷰 전에 다음 명령어를 먼저 실행하세요:

    npm run test       # Vitest 테스트 스위트
    npm run build      # TypeScript 타입 검사 + 빌드

- 테스트 실패 시 → 최우선 버그로 보고
- 빌드 실패 시 → 타입 오류를 최우선으로 보고
- 두 단계 모두 통과한 경우에만 2단계로 진행

## 2단계: 코드 리뷰 (AI 리뷰)

1. 샌드박스/프로덕션 경로 일관성
2. API 응답 형태가 프론트엔드 기대치와 일치하는지
3. SELECT 절 완전성
4. 롤백이 포함된 오류 처리
5. 낙관적 업데이트 경쟁 조건

## 3단계: 수정된 각 버그에 대해 회귀 테스트 제안

워크플로우

사용자: "버그체크 해줘" (혹은 "/bug-check")
  │
  ├─ 1단계: npm run test
  │   ├─ 실패 → 버그를 기계적으로 발견 (AI 판단 불필요)
  │   └─ 통과 → 계속
  │
  ├─ 2단계: npm run build
  │   ├─ 실패 → 타입 오류를 기계적으로 발견
  │   └─ 통과 → 계속
  │
  ├─ 3단계: AI 코드 리뷰 (알려진 사각지대 염두)
  │   └─ 발견 사항 보고
  │
  └─ 4단계: 각 수정에 대해 회귀 테스트 작성
      └─ 다음 버그 검사에서 수정 사항 파괴 여부 확인

일반적인 AI 회귀 패턴

패턴 1: 샌드박스/프로덕션 경로 불일치

빈도: 가장 흔함 (4건 중 3건의 회귀에서 관찰됨)

// 실패: AI가 프로덕션 경로에만 필드를 추가함
if (isSandboxMode()) {
  return { data: { id, email, name } };  // 새 필드 누락
}
// 프로덕션 경로
return { data: { id, email, name, notification_settings } };

// 통과: 두 경로 모두 동일한 형태를 반환해야 함
if (isSandboxMode()) {
  return { data: { id, email, name, notification_settings: null } };
}
return { data: { id, email, name, notification_settings } };

이를 잡는 테스트:

it("샌드박스와 프로덕션이 동일한 필드를 반환한다", async () => {
  // 테스트 환경에서는 샌드박스 모드가 강제로 켜짐
  const res = await GET(createTestRequest("/api/user/profile"));
  const { json } = await parseResponse(res);

  for (const field of REQUIRED_FIELDS) {
    expect(json.data).toHaveProperty(field);
  }
});

패턴 2: SELECT 절 누락

빈도: Supabase/Prisma에서 새 컬럼 추가 시 흔함

// 실패: 새 컬럼이 응답에 추가되었지만 SELECT에는 없음
const { data } = await supabase
  .from("users")
  .select("id, email, name")  // notification_settings 없음
  .single();

return { data: { ...data, notification_settings: data.notification_settings } };
// → notification_settings가 항상 undefined

// 통과: SELECT * 사용 또는 새 컬럼을 명시적으로 포함
const { data } = await supabase
  .from("users")
  .select("*")
  .single();

패턴 3: 오류 상태 누출

빈도: 보통 — 기존 컴포넌트에 오류 처리를 추가할 때

// 실패: 오류 상태가 설정되었지만 이전 데이터가 지워지지 않음
catch (err) {
  setError("로딩 실패");
  // reservations에는 여전히 이전 탭의 데이터가 표시됨!
}

// 통과: 오류 발생 시 관련 상태를 지움
catch (err) {
  setReservations([]);  // 오래된 데이터 지우기
  setError("로딩 실패");
}

패턴 4: 적절한 롤백 없는 낙관적 업데이트

// 실패: 실패 시 롤백 없음
const handleRemove = async (id: string) => {
  setItems(prev => prev.filter(i => i.id !== id));
  await fetch(`/api/items/${id}`, { method: "DELETE" });
  // API가 실패하면 UI에서는 항목이 사라졌지만 DB에는 남아 있음
};

// 통과: 이전 상태를 캡처하고 실패 시 롤백
const handleRemove = async (id: string) => {
  const prevItems = [...items];
  setItems(prev => prev.filter(i => i.id !== id));
  try {
    const res = await fetch(`/api/items/${id}`, { method: "DELETE" });
    if (!res.ok) throw new Error("API 오류");
  } catch {
    setItems(prevItems);  // 롤백
    alert("삭제에 실패했습니다");
  }
};

전략: 버그가 발견된 곳을 테스트하라

100% 커버리지를 목표로 하지 마세요. 대신:

/api/user/profile 에서 버그 발견 → profile API에 대한 테스트 작성
/api/user/messages 에서 버그 발견 → messages API에 대한 테스트 작성
/api/user/favorites 에서 버그 발견 → favorites API에 대한 테스트 작성
/api/user/notifications 에서 버그 없음 → 테스트를 작성하지 않음 (아직은)

이것이 AI 개발에 효과적인 이유:

  1. AI는 동일한 유형의 실수를 반복하는 경향이 있습니다
  2. 버그는 복잡한 영역(인증, 다중 경로 로직, 상태 관리)에 집중됩니다
  3. 일단 테스트되면, 해당 정확한 회귀는 다시 발생할 수 없습니다
  4. 테스트 수는 버그 수정과 함께 자연스럽게 증가합니다 — 낭비되는 노력 없음

빠른 참조

AI 회귀 패턴테스트 전략우선순위
샌드박스/프로덕션 불일치샌드박스 모드에서 동일한 응답 형태 주장높음
SELECT 절 누락응답의 모든 필수 필드 주장높음
오류 상태 누출오류 시 상태 정리 주장중간
롤백 누락API 실패 시 상태 복원 주장중간
타입 캐스트로 null 가림필드가 undefined가 아님을 주장중간

DO / DON'T

DO:

  • 버그를 발견한 직후 테스트를 작성하세요 (가능하다면 수정하기 전에)
  • 구현이 아닌 API 응답 형태를 테스트하세요
  • 모든 버그 검사의 첫 단계로 테스트를 실행하세요
  • 테스트를 빠르게 유지하세요 (샌드박스 모드에서 총 1초 미만)
  • 방지하는 버그의 이름을 테스트에 사용하세요 (예: "BUG-R1 회귀")

DON'T:

  • 한 번도 버그가 발생하지 않은 코드에 테스트를 작성하지 마세요
  • AI의 자체 리뷰를 자동화된 테스트의 대체재로 신뢰하지 마세요
  • "단지 모의 데이터일 뿐"이라는 이유로 샌드박스 경로 테스트를 건너뛰지 마세요
  • 단위 테스트로 충분할 때 통합 테스트를 작성하지 마세요
  • 커버리지 비율을 목표로 하지 마세요 — 회귀 방지를 목표로 하세요

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

api-connector-builder

Build a new API connector or provider by matching the target repo

관련 스킬