// 이 파일이 하는 일: "테스트 코드 입문" 코스 — 테스트가 왜 '미래의 나를 지키는 보험'인지에서
// 출발해, given-when-then 구조, 우리 백엔드의 실제 ProgressServiceTest.java 해부,
// 좋은 테스트의 조건, 경계값 공략, 리팩터링과의 관계, 그리고 직접 테스트를 돌려 보는
// 실습까지 8개 섹션으로 안내하는 정적 학습 페이지.
// 학습 포인트: API 호출이 없는 '내용 고정' 페이지다. 스타일은 global.css의
// 가이드 전용 클래스(step-card, code-block, tip 등)를 재사용한다 — 색을 여기서 하드코딩하지 않는다.
// 코드 예제는 JSX 중괄호/백틱 충돌을 피하려고 파일 상단의 백틱 문자열 상수로 정의한다.

import { Link } from 'react-router-dom';

// ── 코드 예제 · 텍스트 다이어그램 상수들 ──

const CODE_MANUAL_VS_AUTO = `수동 테스트 vs 자동 테스트 — 기능이 30개일 때

수동 테스트                          자동 테스트
──────────────────────────      ──────────────────────────
30개 화면을 매번 손으로 클릭          명령 한 번(▶)에 전부 실행
한 바퀴 도는 데 30분+               수 초 ~ 수십 초
피곤하면 3~4개는 건너뜀             단 하나도 안 빼먹음
"아마 되겠지" 하고 배포              초록불을 보고 배포
버그를 사용자가 먼저 발견            버그를 테스트가 먼저 발견

→ 코드를 고칠 때마다 이 차이가 반복해서 쌓입니다.`;

const CODE_GWT = `// 단위 테스트의 3막 구조 — given / when / then

@Test
void 강의를_완료하면_진도율이_올라간다() {
    // given(무대 준비): 이런 상황이 있다고 치자
    Student student = new Student("김미림");
    Course course = new Course("네트워크의 이해", 10); // 강의 10개짜리

    // when(사건 발생): 테스트하려는 딱 그 동작 하나
    student.complete(course.lesson(1));

    // then(결과 검증): 그래서 이렇게 됐어야 한다
    assertThat(student.progressOf(course)).isEqualTo(10); // 10%
}

// 연극과 똑같아요.
// given = 무대 세팅, when = 주인공의 행동, then = 관객이 확인하는 결말.
// 이 셋이 눈에 보이게 나뉘어 있으면 남이 읽어도 3초 만에 이해됩니다.`;

const CODE_PROGRESS_TEST = `// backend/src/test/java/.../ProgressServiceTest.java 中

@Test
void 이미_완료한_강의를_다시_완료해도_진도율은_그대로다() {
    // given: 강의 10개짜리 코스에서 1강을 이미 완료한 학생
    Progress progress = Progress.of(studentId, courseId, totalLessons(10));
    progress.completeLesson(1L);

    // when: 같은 1강을 한 번 더 완료 처리 (새로고침 연타 상황!)
    progress.completeLesson(1L);

    // then: 진도율은 여전히 10% — 20%로 뻥튀기되면 안 된다
    assertThat(progress.percent()).isEqualTo(10);
    assertThat(progress.completedCount()).isEqualTo(1);
}`;

const CODE_PROGRESS_ANATOMY = `이 테스트 한 편을 해부해 보면:

① 메서드 이름이 한글 문장
   "이미 완료한 강의를 다시 완료해도 진도율은 그대로다"
   → 테스트 목록만 읽어도 명세서(스펙)가 됩니다.

② new / of 로 직접 객체 생성 — DB도, 서버도 안 띄움
   → 그래서 이 테스트는 0.01초 만에 끝나요. (단위 테스트!)

③ 검증(assert)이 핵심 시나리오를 정확히 겨냥
   percent()가 10인지 + completedCount()가 1인지, 두 각도에서 확인.

④ 그리고 이 테스트, 실화 기반입니다.
   완료 버튼을 연타하면 진도율이 2배로 오르던 버그가 실제로 있었고,
   고친 뒤 "다시는 재발하지 마라"고 못 박아 둔 게 이 테스트예요.
   → 테스트는 버그의 묘비명이자, 부활 방지 부적입니다.`;

const CODE_FIRST = `좋은 단위 테스트의 조건 — 특히 이 두 가지

빠르다 (Fast)
  전체 테스트가 커피 한 모금 마시기 전에 끝나야
  "고칠 때마다 돌리는" 습관이 생깁니다.
  5분 걸리면? 아무도 안 돌리고, 안 돌리는 테스트는 없는 테스트예요.

독립적이다 (Independent)
  테스트끼리 순서·데이터를 공유하면 안 됩니다.
  A가 만든 데이터를 B가 쓰면 → A만 지워도 B가 터지는
  "도미노 테스트"가 돼요. 각 테스트는 자기 무대(given)를
  자기가 차리고, 혼자 돌려도 통과해야 합니다.

그 외: 반복 가능(어제도 오늘도 같은 결과),
       자가 검증(사람이 로그를 눈으로 안 봐도 초록/빨강으로 판정).`;

const CODE_BOUNDARY = `경계값 분석 — 버그는 '가장자리'에 삽니다

진도율(0~100%)을 테스트한다면?

  47% 같은 어중간한 값 1개보다, 아래 가장자리들이 훨씬 잘 잡아요:

  값                    노리는 버그
  ─────────────────────────────────────────────
  강의 0개 완료 → 0%     0으로 나누기 에러는 없나?
  1개 완료 → 딱 1칸      반올림이 이상하지 않나?
  전부 완료 → 정확히 100  99.999…%로 끝나 버리진 않나?
  전체 강의 0개인 코스    분모가 0! 제일 위험한 손님
  같은 강의 2번 완료      중복 처리 (아까 그 실화)

수학 시험과 같아요 — 함정 문제는 늘 x=0, 경계 바로 안팎에서 나오죠.
테스트 케이스를 고를 때도 "정상적인 가운데" 말고 "아슬아슬한 끝"을 노리세요.`;

const CODE_REFACTOR = `테스트가 있을 때 vs 없을 때 — 리팩터링 풍경

테스트 없음                         테스트 있음
──────────────────────────      ──────────────────────────
"이 코드 좀 지저분한데...            과감하게 구조를 갈아엎음
 건드렸다 터지면 어쩌지"              ↓
  ↓                              ▶ 테스트 실행 (10초)
결국 안 건드림                       ↓
  ↓                              초록불 → 안심하고 커밋
지저분한 코드 위에                   빨간불 → "아, 이 케이스를
또 지저분한 코드가 쌓임                깜빡했네" 하고 즉시 수정

→ 테스트는 안전그물입니다. 그물이 있어야
  공중제비(리팩터링)를 시도할 용기가 생겨요.`;

const CODE_RUN_TESTS = `# 우리 백엔드 테스트 전체 실행 — 두 가지 방법

# 방법 1) IntelliJ에서 (추천)
#   backend/src/test/java 폴더에서 마우스 오른쪽 클릭
#   → "Run 'All Tests'" 또는 테스트 클래스 옆의 초록 ▶ 버튼 클릭
#   → 아래 실행 창에 초록 체크(✓)들이 주르륵!

# 방법 2) 터미널에서 (backend 폴더에서)
mvn test

# 이런 결과가 보이면 성공:
[INFO] Running dev.awesomedev.mirim.service.ProgressServiceTest
[INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0
...
[INFO] BUILD SUCCESS`;

const CODE_QA02 = `# 도전: 테스트 케이스 1개 추가하기 (티켓 QA-02)

# ProgressServiceTest.java 에 아직 없는 경계값 케이스:
#   "강의가 0개인 코스의 진도율을 물으면?"
#   → 0으로 나누기 폭발 없이, 얌전히 0%가 나와야 한다.

@Test
void 강의가_하나도_없는_코스의_진도율은_0이다() {
    // given: 전체 강의 수가 0개인 코스 (분모가 0인 위험한 상황!)
    Progress progress = Progress.of(studentId, courseId, totalLessons(0));

    // when + then: 예외 없이 0이 나와야 한다
    assertThat(progress.percent()).isEqualTo(0);
}

# 이 테스트를 추가하고 ▶ 실행 →
#   초록불: 이미 방어돼 있던 것. 축하해요, 명세 하나를 문서화했습니다.
#   빨간불: 진짜 버그를 찾은 겁니다! 멘토와 함께 고쳐 보세요.
# 완료하면 Gitea(edu.awesomedevapp.com:3000)의 QA-02 티켓에
# 결과 스크린샷과 함께 코멘트를 남겨 주세요.`;

// ── 이 페이지 안에서만 쓰는 작은 부품들 ──
// 학습 포인트: 같은 모양이 반복되면 컴포넌트로 뽑는다. props만 바꿔 재사용.
function Section({ n, title, sub, children }) {
  return (
    <section className="step-card" id={`sec-${n}`}>
      <div className="step-head">
        <span className="step-num">{n}</span>
        <div>
          <h3>{title}</h3>
          {sub && <span className="step-sub">{sub}</span>}
        </div>
      </div>
      <div className="step-body">{children}</div>
    </section>
  );
}

function Code({ children }) {
  return <pre className="code-block"><code>{children}</code></pre>;
}

const SECTIONS = [
  { n: 1, label: '테스트 = 보험' },
  { n: 2, label: '수동 테스트의 한계' },
  { n: 3, label: 'given-when-then' },
  { n: 4, label: '실제 테스트 해부' },
  { n: 5, label: '좋은 테스트의 조건' },
  { n: 6, label: '경계값을 노려라' },
  { n: 7, label: '리팩터링과 테스트' },
  { n: 8, label: '실습: 직접 돌려 보기' },
];

export default function TestingPage() {
  return (
    <div>
      {/* 히어로: 이 코스가 어디서 출발해 어디까지 가는지 */}
      <div className="hero">
        <div className="eyebrow">Course · 소프트웨어</div>
        <h1>테스트 코드 입문<br />— 미래의 나를 지키는 보험 들기</h1>
        <p>
          "코드가 잘 돌아가는지 매번 손으로 눌러 보는" 세계에서 벗어나,
          컴퓨터가 대신 검사해 주는 <strong>테스트 코드</strong>의 세계로 들어갑니다.
          마지막엔 우리 플랫폼 백엔드의 <strong>진짜 테스트를 직접 실행</strong>하고,
          케이스 하나를 추가하는 것까지 해 봅니다.
        </p>
        <div className="chip-row">
          <span className="chip">예상 소요 70분</span>
          <span className="chip">실습 2개 + 도전 과제 1개</span>
          <span className="chip">준비물: IntelliJ + 우리 backend 코드</span>
        </div>
      </div>

      {/* 섹션 바로가기 */}
      <nav className="pill-nav">
        {SECTIONS.map((s) => (
          <a key={s.n} href={`#sec-${s.n}`}>
            <b>{s.n}</b>
            {s.label}
          </a>
        ))}
      </nav>

      <Section n={1} title="테스트는 미래의 나를 지키는 보험" sub="지금 5분 vs 나중의 밤샘">
        <p>
          테스트 코드란 <strong>"내 코드가 약속대로 동작하는지 검사하는 또 다른 코드"</strong>예요.
          진도율 계산 함수를 만들었다면, "강의 10개 중 1개 완료 → 10%가 나와야 해"라고
          검사하는 코드를 옆에 하나 더 써 두는 거죠.
        </p>
        <p>
          이게 왜 <strong>보험</strong>이냐면 — 보험은 사고가 <strong>나기 전에</strong> 들잖아요.
          코드도 마찬가지예요. 지금은 멀쩡해 보여도, 3개월 뒤의 나(혹은 팀 동료)가
          이 코드를 고치다가 나도 모르게 뭔가를 부술 수 있어요. 그때 테스트가 있으면
          <strong> 빨간불이 켜지며 즉시 알려 주고</strong>, 없으면 사용자가 "진도율이 이상해요"
          하고 신고할 때까지 아무도 모릅니다.
        </p>
        <p>
          그리고 보험처럼, 보험료(테스트 작성 시간)는 지금 조금씩 내지만
          사고가 났을 때 돌려받는 보험금(밤샘 디버깅 면제)은 훨씬 큽니다.
        </p>
        <div className="tip">
          <b>용어 정리</b> 이 코스에서 다루는 건 <strong>단위 테스트</strong>(unit test) —
          함수·클래스 같은 <span className="icode">작은 부품 하나</span>를 떼어 검사하는 테스트예요.
          우리 Spring Boot 백엔드에서는 <span className="icode">JUnit</span>이라는 도구로 작성합니다.
        </div>
      </Section>

      <Section n={2} title="수동 테스트의 한계" sub="매번 다 눌러볼 수는 없다">
        <p>
          "나 테스트 했는데?" — 맞아요, 브라우저 열고 버튼 눌러 보는 것도 테스트예요.
          <strong> 수동 테스트</strong>죠. 기능이 3개일 땐 이걸로 충분합니다.
          문제는 기능이 30개, 300개가 될 때예요.
        </p>
        <Code>{CODE_MANUAL_VS_AUTO}</Code>
        <p>
          더 무서운 건 <strong>"고친 곳 말고 딴 데가 터지는"</strong> 경우예요.
          진도율 코드를 고쳤는데 출석 기능이 망가진다든가. 수동 테스트로는 고친 곳
          근처만 눌러 보게 되니 이런 <strong>연쇄 붕괴</strong>를 못 잡아요.
          자동 테스트는 매번 <strong>전 과목 모의고사</strong>를 몇 초 만에 다시 보는 것과 같아서,
          엉뚱한 과목의 점수 하락(=다른 기능의 고장)도 바로 드러납니다.
        </p>
        <div className="warn">
          <b>오해 금지</b> 자동 테스트가 수동 테스트를 100% 대체하는 건 아니에요.
          "버튼 위치가 어색하다" 같은 사용성은 여전히 사람 눈이 필요합니다.
          자동 테스트가 맡는 건 <strong>"로직이 약속대로 동작하는가"</strong>라는
          지루하고 반복적인 검사 — 기계가 제일 잘하는 일이죠.
        </div>
      </Section>

      <Section n={3} title="단위 테스트의 구조 — given · when · then" sub="모든 테스트는 3막짜리 연극이다">
        <p>
          테스트 코드는 처음 보면 낯설지만, 사실 전 세계 개발자들이 똑같은
          <strong> 3막 구조</strong>로 씁니다. 상황을 차리고(<strong>given</strong>),
          동작을 딱 하나 실행하고(<strong>when</strong>), 결과를 확인한다(<strong>then</strong>).
        </p>
        <Code>{CODE_GWT}</Code>
        <ol className="olist">
          <li><strong>given</strong> — 무대 준비. 테스트에 필요한 객체·데이터를 만들어요. "강의 10개짜리 코스에 김미림 학생이 있다고 치자."</li>
          <li><strong>when</strong> — 사건 발생. 검사하려는 <strong>딱 그 동작 하나</strong>만 호출해요. 여기서 두세 가지를 한꺼번에 하면 나중에 실패했을 때 범인을 못 찾습니다.</li>
          <li><strong>then</strong> — 결말 확인. <span className="icode">assertThat(실제값).isEqualTo(기대값)</span> — "실제로 이랬는가?"를 단언(assert)해요. 기대와 다르면 테스트가 <strong>빨간불</strong>로 실패합니다.</li>
        </ol>
        <svg className="diagram" viewBox="0 0 640 260" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="given-when-then 3단 구조: 무대 준비, 사건 발생, 결과 검증으로 이어지는 흐름 도해">
          <rect x="20" y="30" width="180" height="170" rx="8" fill="var(--card)" stroke="var(--teal)" strokeWidth="1.5" />
          <text x="110" y="58" textAnchor="middle" fontSize="12" fill="var(--muted)">1막 · 무대 준비</text>
          <text x="110" y="84" textAnchor="middle" fontSize="15" fontWeight="bold" fill="var(--teal)">given</text>
          <text x="110" y="112" textAnchor="middle" fontSize="12.5" fill="var(--ink)">필요한 객체·데이터 준비</text>
          <text x="110" y="138" textAnchor="middle" fontSize="12" fill="var(--muted)">강의 10개짜리 코스에</text>
          <text x="110" y="156" textAnchor="middle" fontSize="12" fill="var(--muted)">김미림 학생이 있다고 치자</text>
          <line x1="202" y1="115" x2="224" y2="115" stroke="var(--muted)" strokeWidth="2" />
          <polyline points="218,109 227,115 218,121" fill="none" stroke="var(--muted)" strokeWidth="2" />
          <rect x="230" y="30" width="180" height="170" rx="8" fill="var(--card)" stroke="var(--primary)" strokeWidth="1.5" />
          <text x="320" y="58" textAnchor="middle" fontSize="12" fill="var(--muted)">2막 · 사건 발생</text>
          <text x="320" y="84" textAnchor="middle" fontSize="15" fontWeight="bold" fill="var(--primary)">when</text>
          <text x="320" y="112" textAnchor="middle" fontSize="12.5" fill="var(--ink)">동작 딱 하나만 실행</text>
          <text x="320" y="138" textAnchor="middle" fontSize="12" fill="var(--muted)">1강을 완료한다</text>
          <text x="320" y="156" textAnchor="middle" fontSize="12" fill="var(--muted)">(두 개 이상은 금지!)</text>
          <line x1="412" y1="115" x2="434" y2="115" stroke="var(--muted)" strokeWidth="2" />
          <polyline points="428,109 437,115 428,121" fill="none" stroke="var(--muted)" strokeWidth="2" />
          <rect x="440" y="30" width="180" height="170" rx="8" fill="var(--card)" stroke="var(--amber)" strokeWidth="1.5" />
          <text x="530" y="58" textAnchor="middle" fontSize="12" fill="var(--muted)">3막 · 결과 검증</text>
          <text x="530" y="84" textAnchor="middle" fontSize="15" fontWeight="bold" fill="var(--amber)">then</text>
          <text x="530" y="112" textAnchor="middle" fontSize="12.5" fill="var(--ink)">assertThat으로 단언</text>
          <text x="530" y="138" textAnchor="middle" fontSize="12" fill="var(--muted)">진도율은 10%여야 한다</text>
          <circle cx="150" cy="231" r="6" fill="var(--teal)" />
          <text x="163" y="236" fontSize="12.5" fill="var(--ink)">기대와 같다 → 초록불(통과)</text>
          <circle cx="360" cy="231" r="6" fill="var(--rose)" />
          <text x="373" y="236" fontSize="12.5" fill="var(--ink)">기대와 다르다 → 빨간불(실패)</text>
        </svg>
        <p className="muted" style={{ fontSize: 12.5, textAlign: 'center', marginTop: 2 }}>그림: given(무대 준비) → when(사건 발생) → then(결과 검증) — 단위 테스트의 3막 구조</p>
        <p>
          이 구조의 진짜 힘은 <strong>읽는 사람</strong>한테 있어요. 주석 세 줄만 따라 읽으면
          "아, 이 코드는 이런 상황에서 이렇게 동작해야 하는구나"가 바로 보이거든요.
          잘 쓴 테스트는 그 자체로 <strong>살아있는 사용 설명서</strong>입니다.
        </p>
      </Section>

      <Section n={4} title="우리 코드 해부: ProgressServiceTest.java" sub="실화를 바탕으로 한 테스트">
        <p>
          이제 진짜 우리 플랫폼 코드를 봅시다. 여러분이 강의를 "완료"할 때마다 도는
          진도율 로직에는 이미 테스트가 붙어 있어요. 그중 한 편:
        </p>
        <Code>{CODE_PROGRESS_TEST}</Code>
        <Code>{CODE_PROGRESS_ANATOMY}</Code>
        <p>
          특히 ④번을 기억하세요. 좋은 테스트 케이스는 상상이 아니라 <strong>실제 사고</strong>에서
          나오는 경우가 많아요. 버그를 고치면 "이 버그를 재현하는 테스트"를 함께 남기는 것 —
          그래야 누가 나중에 코드를 고쳐서 같은 버그가 부활해도 테스트가 즉시 잡아냅니다.
        </p>
        <div className="tip">
          <b>직접 확인해 보기</b> IntelliJ에서 <span className="kbd">Shift</span> 두 번 연타
          (Search Everywhere) → <span className="icode">ProgressServiceTest</span> 입력 →
          파일을 열어 보세요. 테스트 메서드 이름들만 위에서 아래로 죽 읽어 보기 —
          코드를 한 줄도 안 읽었는데 진도율 기능의 <strong>규칙 목록</strong>이
          머릿속에 그려지면, 그게 바로 "테스트 = 명세서"의 체험입니다.
        </div>
      </Section>

      <Section n={5} title="좋은 테스트의 조건" sub="빠르고, 독립적이어야 매일 돌린다">
        <p>
          테스트도 코드라서 잘 쓴 테스트와 못 쓴 테스트가 있어요. 조건은 여러 가지지만,
          입문 단계에서 꼭 챙길 것은 두 가지 — <strong>빠를 것</strong>, 그리고
          <strong> 서로 독립적일 것</strong>입니다.
        </p>
        <Code>{CODE_FIRST}</Code>
        <p>
          "빠르다"가 왜 그렇게 중요할까요? 테스트의 가치는 <strong>자주 돌리는 데서</strong> 나오거든요.
          소화기가 아무리 좋아도 창고 깊숙이 있으면 못 쓰는 것처럼, 테스트도 실행이 귀찮으면
          존재하지 않는 것과 같아요. 그래서 단위 테스트는 DB나 서버 없이
          <strong> 순수한 자바 객체만으로</strong> 돌게 만드는 걸 우선합니다 —
          섹션 4의 테스트가 <span className="icode">new</span>로만 무대를 차린 이유예요.
        </p>
        <p>
          "독립적"은 <strong>시험의 공정성</strong>이라고 생각하면 돼요. 각 테스트는 매번
          깨끗한 책상(자기만의 given)에서 시험을 봐야 합니다. 앞 테스트가 남긴 낙서(공유 데이터)에
          기대는 순간, 테스트 실행 <strong>순서만 바뀌어도</strong> 멀쩡한 코드가 실패하는
          미스터리가 시작돼요.
        </p>
      </Section>

      <Section n={6} title="경계값을 노려라" sub="버그는 가운데가 아니라 가장자리에 산다">
        <p>
          테스트 케이스를 무한정 만들 수는 없으니 <strong>잘 고르는 기술</strong>이 필요해요.
          핵심 요령 하나: <strong>경계값</strong>(boundary value)을 노리세요. 버그는 평범한
          한가운데 값이 아니라, 범위가 시작되고 끝나는 <strong>아슬아슬한 가장자리</strong>에서 태어납니다.
        </p>
        <Code>{CODE_BOUNDARY}</Code>
        <p>
          왜 가장자리일까요? 개발자가 코드를 쓸 때 머릿속에 떠올리는 건 대부분
          "정상적인 경우"예요. <span className="icode">0</span>, <span className="icode">비어 있음</span>,
          <span className="icode">딱 최대치</span>, <span className="icode">중복</span> 같은
          끝자락 상황은 상상에서 빠지기 쉽고, 그 빈틈이 그대로 버그가 됩니다.
          놀이기구 키 제한이 "120cm 이상"일 때 정확히 120.0cm인 사람을 태울지 말지 —
          이런 딱 걸치는 지점이 늘 말썽이죠.
        </p>
        <div className="tip">
          <b>실전 요령</b> 어떤 기능이든 테스트를 짜기 전에 종이에 세 칸을 그려 보세요:
          <strong> 텅 빈 경우 / 딱 1개인 경우 / 꽉 찬(최대) 경우</strong>.
          이 세 칸만 챙겨도 버그의 절반 이상을 미리 만납니다.
        </div>
      </Section>

      <Section n={7} title="테스트가 있으면 리팩터링이 무섭지 않다" sub="안전그물 위에서만 공중제비를 돈다">
        <p>
          <strong>리팩터링</strong>은 동작은 그대로 두고 코드의 <strong>구조만</strong> 깨끗하게
          고치는 일이에요. 방 정리와 같죠 — 물건(기능)은 그대로인데 배치만 바꾸는 것.
          문제는 "배치만 바꿨다고 생각했는데 뭔가 없어졌을" 위험입니다.
        </p>
        <Code>{CODE_REFACTOR}</Code>
        <p>
          테스트가 <strong>"동작은 그대로"임을 보증하는 감시자</strong>가 되어 주면, 이 위험이
          사라져요. 구조를 갈아엎고 → 테스트 실행 → 전부 초록불이면 "동작은 안 변했다"는
          증거를 손에 쥔 겁니다. 서커스 단원이 안전그물이 있을 때만 고난도 기술을 연습하듯,
          개발자도 테스트가 있을 때 과감해질 수 있어요.
        </p>
        <p>
          거꾸로 말하면, 테스트 없는 코드는 <strong>아무도 청소하려 들지 않는 방</strong>이 됩니다.
          건드리기 무서우니까요. 그렇게 지저분함이 쌓인 코드를 개발자들은
          <strong> 레거시</strong>라고 부르며 서로 떠넘기죠. 여러분이 지금 테스트를 배우는 건
          그런 방을 만들지 않는 습관을 처음부터 들이는 거예요.
        </p>
      </Section>

      <Section n={8} title="실습: 우리 백엔드 테스트 실행해 보기" sub="▶ 버튼 한 번, 그리고 도전 과제 QA-02">
        <p>
          이제 직접 돌려 봅시다. 우리 플랫폼 backend 프로젝트를 IntelliJ로 연 상태에서 시작하세요.
        </p>
        <div className="tip">
          <b>직접 확인해 보기 ①</b> 아래 방법대로 <strong>전체 테스트를 실행</strong>해 보세요.
          초록 체크가 줄줄이 뜨는 순간의 안도감 — 그게 테스트가 매일 주는 선물입니다.
          일부러 <span className="icode">Progress</span> 코드의 숫자 하나를 살짝 바꾼 뒤 다시 돌려서
          <strong> 빨간불이 뜨는 것</strong>까지 보고, 원상 복구하세요. (빨간불을 봐야 초록불을 믿게 돼요!)
        </div>
        <Code>{CODE_RUN_TESTS}</Code>
        <p>
          다음은 오늘 배운 걸 전부 쓰는 <strong>도전 과제</strong>예요. 섹션 6에서 본 경계값 표에
          "전체 강의 0개인 코스"가 있었죠? 그 케이스가 실제 테스트 파일에는 아직 없습니다.
          여러분이 채워 넣을 차례예요.
        </p>
        <div className="tip">
          <b>직접 확인해 보기 ② — 도전 과제 (티켓 QA-02)</b> given-when-then 구조(섹션 3)로
          경계값 케이스(섹션 6) 하나를 <span className="icode">ProgressServiceTest.java</span>에
          추가하고 실행해 보세요. 아래 뼈대를 참고하되, 메서드 이름은 여러분의 문장으로!
        </div>
        <Code>{CODE_QA02}</Code>
        <div className="warn">
          <b>막히면</b> 혼자 30분 이상 붙잡지 마세요. Gitea 티켓 QA-02에 "여기까지 했고,
          여기서 막혔다"를 남기는 것도 훌륭한 진행이에요. 막힌 지점을 정확히 설명하는 능력이
          테스트 작성 능력만큼 중요합니다.
        </div>
      </Section>

      <div className="step-card">
        <div className="step-body">
          <h3 style={{ marginBottom: 6 }}>🧪 여기까지 왔다면</h3>
          <p className="muted">
            테스트가 <strong>미래의 나를 지키는 보험</strong>이라는 것, given-when-then이라는
            <strong> 3막 구조</strong>, 버그가 사는 <strong>경계값</strong>, 그리고 테스트라는
            안전그물 위에서만 가능한 <strong>리팩터링</strong>까지 — 직접 ▶를 눌러 초록불과
            빨간불을 모두 봤다면 이 코스는 통과입니다. 도전 과제(QA-02)를 끝냈다면{' '}
            <Link to="/learn/git-deep"><strong>Git 협업 기초</strong></Link> 코스에서 방금 만든
            테스트를 커밋·푸시해 리뷰받는 흐름으로 이어 보세요. 백엔드 코드 자체가 궁금해졌다면{' '}
            <Link to="/learn/spring-intro"><strong>Spring Boot 백엔드 입문</strong></Link>이 다음 정거장입니다.
          </p>
        </div>
      </div>
    </div>
  );
}
