7강 실습 중심 ⏱ 약 60분

 

0. 학습 목표

→ 재고가 부족한 상품을 조회하는 기능을, VS Code에 연동된 Claude Code의 도움으로 만들고 검증합니다.

더보기

0.1 학습 목적과 선수 조건

 

이 강의에서는 어려운 Python 문법이나 복잡한 설계를 다루지 않습니다. 다음 세 가지만 확실히 이해하는 것이 목표입니다.

  • 내가 원하는 기능을 한두 문장으로 정리해서 Claude Code에 전달하는 방법
  • Claude Code가 만든 코드를 실행하고, 결과가 맞는지 확인하는 방법
  • 같은 결과를 실제 데이터베이스와 대조해서 "진짜 완료되었는지" 판단하는 방법

 

이 강의는 다음 상태에서 시작합니다.

  • 6강에서 VS Code에 Claude Code를 연동했습니다.
  • 5강에서 만든 docs/database/schema.md 등 문서 네 개와 CLAUDE.md 규칙이 있습니다.
  • inventory DB에 products 8건, stock_logs 16건, operation_requests 0건이 있습니다.

 

 

 

0.2 진행 순서

 

6강 실습 상태 확인
  ↓
무엇을 만들지 문장으로 정하기
  ↓
Claude Code에 구현 계획 요청하기
  ↓
DB에 연결하는 코드 만들기
  ↓
재고를 조회하는 코드 만들기
  ↓
결과를 정리하는 코드 만들기
  ↓
테스트로 확인하기
  ↓
MCP 조회 결과와 비교하기

 

 

 

0.3 완성할 결과물

 

inventory-mysql-app/
└── app/
    ├── __init__.py
    ├── db.py                       # 신규: DB에 연결하는 코드
    ├── repositories/
    │   ├── __init__.py
    │   └── inventory_repository.py # 신규: 재고를 조회하는 코드
    └── services/
        ├── __init__.py
        └── inventory_service.py    # 신규: 결과를 정리하는 코드

tests/
└── test_inventory_service.py       # 신규: 자동 확인 코드 2개

 

파일이 세 개로 나뉘는 이유는 간단합니다. DB에 연결하는 부분, SQL로 조회하는 부분, 결과를 계산·정리하는 부분을 각각 다른 파일에 두면, 나중에 한 부분만 고칠 때 다른 부분을 건드리지 않아도 됩니다.

 

 



0.4 구현할 기능과 프로그램에서의 역할

 

0.3에서 만든 파일들이 실제로 처리하는 기능은 다음 한 문장으로 정리됩니다.

 

재고 수량이 재주문 기준 수량 이하로 내려간 상품을, 부족한 수량이 많은 순서로 조회하는 기능

 

이 요구사항은 2장에서 조건·정렬·결과 세 문장으로 다시 정리한 뒤, 3장에서 Claude Code에 그대로 전달합니다. 지금 단계에서는 이 기능이 무엇을 하는 기능인지 전체 프로그램에서 어떤 역할을 맡는지를 먼저 확인합니다.

 

구분 이번 기능의 위치
지금 만드는 것 재고 부족 상품을 SELECT로만 조회하는 기능.
데이터를 바꾸지 않는다.
사용 계정 inventory_app 계정(2강에서 생성, 조회 전용 권한)만 사용한다.
8강에서의 사용 이번 강의의 inventory_service.py를 코드 수정 없이 그대로 불러와, PySide6 화면의 표에 결과를 채운다.
9~10강과의 관계 재고를 실제로 줄이는 출고 기능은 별도의 트랜잭션으로 9강에서 새로 만든다. 이번 조회 기능은 출고 대상을 확인하는 참고 자료로만 쓰이고, 출고 기능이 이 코드를 직접 수정하지는 않는다.

✔ 핵심: 오늘 만드는 코드는 "조회 전용"입니다. 8강 화면은 이 코드를 그대로 재사용하고, 재고를 바꾸는 기능은 이후 강의에서 별도로 만듭니다.

 

 

 

 

0.4 학습 목표

 

7강을 마치면 다음 작업을 할 수 있습니다.

  1. 원하는 기능을 조건, 정렬, 결과로 나누어 문장으로 쓸 수 있습니다.
  2. Claude Code에 구현 계획을 요청하고, 계획이 맞는지 확인할 수 있습니다.
  3. DB 연결, 조회, 결과 정리 코드가 왜 나뉘어 있는지 설명할 수 있습니다.
  4. 완성된 코드를 실행하고 결과를 눈으로 확인할 수 있습니다.
  5. 간단한 자동 확인 코드(테스트)를 실행하고 통과 여부를 읽을 수 있습니다.
  6. Python 결과와 MCP 조회 결과가 같은지 비교할 수 있습니다.

 

1. 6강 실습 상태 확인

→ VS Code와 Claude Code 세션, MCP 연결, 기준 데이터 8 / 16 / 0을 확인하고 시작합니다.

더보기

1.1 VS Code와 세션 확인하기

 

[화면 캡처: VS Code Claude Code 세션에서 /mcp 결과에 mysql-inventory가 connected로 표시된 화면]

 

VS Code로 inventory-mysql-app 폴더를 엽니다. 이미 열려 있다면 그대로 사용합니다.

code ~/projects/inventory-mysql-app

 

VS Code 통합 터미널에서 가상환경을 켭니다.

source .venv/bin/activate

 

VS Code 사이드바에서 Claude Code 세션을 열고 연결 상태를 확인합니다.

/mcp

 

 

 

 

1.2 기준 데이터 확인하기

 

Claude Code 세션에 다음과 같이 요청합니다.

inventory DB의 products, stock_logs, operation_requests의 행 수를 확인해줘.

조건:
- 실행할 SELECT SQL을 먼저 보여준다.

내가 SQL을 확인하고 승인하기 전에는 실행하지 마.
[화면 캡처: MCP 조회 결과로 세 테이블 행 수가 표시된 화면]

 

▶ 지금 해보세요

  1. VS Code에서 프로젝트를 열고 가상환경을 켭니다.
  2. /mcp로 연결 상태를 확인합니다.
  3. 세 테이블의 행 수를 조회합니다.

✔ 확인 기준: mysql-inventory가 연결되어 있고, 세 테이블의 행 수가 8 / 16 / 0입니다.

 

2. 무엇을 만들지 문장으로 정하기

→ "재고가 부족한 상품을 보고 싶다"는 생각을 조건·정렬·결과 세 문장으로 정리합니다.

더보기

2.1 세 문장으로 정리하기

 

"재고가 부족한 상품을 조회하고 싶다"라는 말만으로는 Claude Code가 정확한 코드를 만들 수 없습니다.

먼저 다음 세 가지를 문장으로 정합니다.

 

구분 이번 기능에서 정한 내용
조건 현재 재고 수량이 재주문 기준 수량 이하인 상품
정렬 부족한 수량(재주문 기준 − 현재 수량)이 많은 상품부터
결과 상품 번호, 상품명, 현재 수량, 재주문 기준, 부족 수량

 

"부족 수량"은 products 테이블에 저장된 값이 아닙니다. 재주문 기준에서 현재 수량을 빼서 계산해야 하는 값입니다. 이 계산은 5장에서 Python 코드로 처리하기로 정합니다.

✔ 핵심: 조건·정렬·결과가 문장으로 정해지지 않은 채로 요청하면, 코드는 만들어지지만 내가 원한 기능과 다를 수 있습니다.

 

 

 

2.2 schema.md에서 컬럼 이름 확인하기

 

docs/database/schema.md를 열어 products 테이블 부분을 확인합니다.

 

이번에 사용할 컬럼은 다음 네 개입니다.

  • product_id (상품 번호)
  • product_name (상품명)
  • stock_quantity (현재 재고 수량)
  • reorder_level (재주문 기준 수량)

▶ 지금 해보세요

  1. 조건, 정렬, 결과를 각각 한 문장으로 적어 봅니다.
  2. schema.md에서 네 컬럼 이름을 확인합니다.

✔ 확인 기준: 조건·정렬·결과를 각각 한 문장으로 설명할 수 있고, 사용할 컬럼 네 개가 schema.md에 실제로 있습니다.

 

3. Claude Code에 구현 계획 요청하기

→ 문서와 실제 스키마를 근거로 계획을 요청하고, VS Code의 diff 화면으로 파일 변경을 검토합니다.

더보기

3.1 구현 계획 요청하기

 

Claude Code 세션에 다음과 같이 요청합니다.

docs/database/schema.md를 먼저 읽고, 재고 수량이 재주문 기준 이하인
상품을 조회하는 기능을 만들 계획을 세워줘.

조건:
- 조회 조건은 stock_quantity <= reorder_level이다.
- 정렬은 부족 수량(reorder_level - stock_quantity)이 많은 순서다.
- 결과는 상품 번호, 상품명, 현재 수량, 재주문 기준, 부족 수량이다.
- 부족 수량 계산은 SQL이 아니라 Python 코드에서 한다.
- SQL은 app/repositories/inventory_repository.py에만 쓴다.
- app/db.py의 연결 함수는 inventory_app 계정을 쓰고,
  비밀번호는 환경변수로만 받는다.

만들기 전에 사용할 테이블·컬럼과 만들 파일 목록을 먼저 보여줘.
파일을 한 번에 다 만들지 말고, 하나 만들 때마다
diff로 보여주고 내 승인을 기다려줘.

 

 

[화면 캡처: VS Code Claude Code 세션이 근거 문서와 만들 파일 목록을 제시한 화면]

 

 

 

 

3.2 계획 확인하기

 

승인하기 전에 다음만 확인합니다.

  • 만들 파일이 app/db.py, inventory_repository.py, inventory_service.py 세 개인가?
  • 사용하는 테이블이 products 하나인가?

두 가지가 맞으면 승인합니다.

▶ 지금 해보세요

  1. 위 요청을 입력합니다.
  2. 만들 파일 목록과 사용 테이블을 확인합니다.
  3. 맞으면 계획을 승인합니다.

✔ 확인 기준: 만들 파일이 세 개로 제한되어 있고, products 테이블만 사용합니다.

 

4. DB에 연결하는 코드 만들기

→ 비밀번호를 코드에 적지 않고 환경변수로 받아 inventory_app 계정으로 연결하는 함수를 만듭니다.

더보기

4.1 app/db.py 생성 요청하기

 

용어: 환경변수(environment variable) — 운영체제가 프로세스에 전달하는 값입니다. 비밀번호처럼 코드에 직접 적으면 안 되는 값을 담는 데 사용합니다.

 

Claude Code 세션에 다음과 같이 요청합니다.

app/db.py를 만들어줘.

조건:
- INVENTORY_DB_HOST(기본값 127.0.0.1), INVENTORY_DB_PORT(기본값 3306),
  INVENTORY_DB_USER(기본값 inventory_app), INVENTORY_DB_NAME(기본값 inventory)은
  환경변수에 없으면 기본값을 쓴다.
- INVENTORY_DB_PASSWORD는 기본값이 없다. 환경변수에 없으면
  RuntimeError를 발생시킨다.
- create_connection()이라는 함수 하나로 mysql-connector-python 연결을 반환한다.
- 비밀번호는 코드에 직접 적지 않는다.

diff로 보여주고 승인을 기다려줘.

 

 

 

[화면 캡처: VS Code diff 화면에 app/db.py 초안이 표시된 상태]

 

 

 

 

4.2 완성된 코드 확인하기

 

승인하면 다음과 비슷한 코드가 만들어집니다.

import os
import mysql.connector


def create_connection():
    password = os.environ.get("INVENTORY_DB_PASSWORD")
    if not password:
        raise RuntimeError("INVENTORY_DB_PASSWORD 환경변수가 설정되지 않았습니다.")

    return mysql.connector.connect(
        host=os.environ.get("INVENTORY_DB_HOST", "127.0.0.1"),
        port=int(os.environ.get("INVENTORY_DB_PORT", "3306")),
        user=os.environ.get("INVENTORY_DB_USER", "inventory_app"),
        password=password,
        database=os.environ.get("INVENTORY_DB_NAME", "inventory"),
    )

비밀번호가 없으면 연결을 시도하지 않고 RuntimeError를 먼저 발생시킵니다. 잘못된 연결 시도로 오류 메시지가 길어지는 것을 막기 위해서입니다.

▶ 지금 해보세요

  1. 위 요청을 입력하고 diff를 확인한 뒤 승인합니다.
  2. 쉘 프롬프트에서 비밀번호를 환경변수로 설정합니다.

 



4.3 환경변수에 비밀번호 저장하고 테스트

 

# 1. 화면에 비밀번호가 안 보이도록 안전하게 입력받아 변수에 임시 저장
read -s -p "inventory_app 비밀번호: " USER_INPUT
echo  # 줄바꿈용

# 2. 파이썬 코드가 요구하는 정확한 환경 변수명으로 등록 (echo 없이 실행)
export INVENTORY_APP_DB_PASSWORD="$USER_INPUT"

✔ 확인 기준: app/db.py가 생성되어 있고, 비밀번호가 코드 어디에도 적혀 있지 않습니다.

 

# 3. 파이썬 연결 테스트 실행
python3 -c "
from app.db import create_connection    # ✏️ 함수명 확인 필요
conn = create_connection()              # ✏️ 함수명 확인 필요
print('연결 성공:', conn.is_connected())
conn.close()
"

 

5. 재고를 조회하는 코드 만들기

→ SQL 실행은 이 파일 하나에만 둡니다. 다른 파일은 SQL을 직접 쓰지 않습니다.

더보기

5.1 inventory_repository.py 생성 요청하기

 

용어: repository(저장소) — 데이터베이스에 SQL을 실행하는 코드만 모아 두는 파일입니다. 다른 파일은 이 파일이 반환한 값만 사용하고, SQL을 직접 쓰지 않습니다.

 

Claude Code 세션에 다음과 같이 요청합니다.

app/repositories/inventory_repository.py를 만들어줘.

조건:
- fetch_low_stock_products(connection) 함수 하나를 만든다.
- SQL은 다음과 같다.
  SELECT product_id, product_name, stock_quantity, reorder_level
  FROM products
  WHERE stock_quantity <= reorder_level
  ORDER BY product_id ASC
- 결과는 딕셔너리(dict)의 리스트로 반환한다.
- 커서(cursor)는 사용 후 반드시 닫는다.
- 이 파일에서 connection을 새로 만들지 않는다. 인자로 받은 것만 쓴다.
- app/db.py에 생성된 DB 연결 함수명을 사용한다.

diff로 보여주고 승인을 기다려줘.

 

 

[화면 캡처: VS Code diff 화면에 inventory_repository.py 초안이 표시된 상태]

 

 

 

 

5.2 완성된 코드 확인하기

 

승인하면 다음과 비슷한 코드가 만들어집니다.

def fetch_low_stock_products(connection):
    cursor = connection.cursor(dictionary=True)
    try:
        cursor.execute(
            """
            SELECT product_id, product_name, stock_quantity, reorder_level
            FROM products
            WHERE stock_quantity <= reorder_level
            ORDER BY product_id ASC
            """
        )
        return cursor.fetchall()
    finally:
        cursor.close()

cursor(dictionary=True)로 커서를 만들면 각 행이 {"product_id": 3, "product_name": "USB-C 허브", ...} 형태의 딕셔너리로 반환됩니다. 컬럼 순서를 외우지 않고 이름으로 값을 꺼낼 수 있습니다.

try/finally로 커서를 닫는 이유는, SQL 실행 중 오류가 나더라도 커서가 열린 채로 남지 않게 하기 위해서입니다.

▶ 지금 해보세요

  1. 위 요청을 입력하고 diff를 확인합니다.
  2. SQL 문장이 5.1의 조건과 같은지 확인한 뒤 승인합니다.

✔ 확인 기준: fetch_low_stock_products 함수가 있고, SQL 안의 조건절이 stock_quantity <= reorder_level입니다.

 

6. 결과를 정리하는 코드 만들기

→ 부족 수량을 계산하고 정렬하는 코드를 만들고, 직접 실행해 결과를 확인합니다.

더보기

6.1 inventory_service.py 생성 요청하기

 

용어: service(서비스) — SQL 결과를 화면이나 다른 코드가 쓰기 좋은 형태로 가공하는 파일입니다. 계산, 정렬처럼 데이터베이스가 아니라 Python이 처리해야 하는 일을 담당합니다.

 

Claude Code 세션에 다음과 같이 요청합니다.

app/services/inventory_service.py를 만들어줘.

조건:
- get_low_stock_report(connection) 함수 하나를 만든다.
- app/db.py의 create_connection과
  app/repositories/inventory_repository.py의 fetch_low_stock_products를 사용한다.
- 각 상품마다 shortage_quantity = reorder_level - stock_quantity를 계산해
  결과 딕셔너리에 추가한다.
- shortage_quantity가 큰 상품부터 정렬한다.
- 파일 맨 아래에 __main__ 블록을 추가해서, 이 파일을 직접 실행하면
  connection을 만들고 결과를 한 줄씩 출력한 뒤 connection을 닫는다.

diff로 보여주고 승인을 기다려줘.

 

 

 

6.2 완성된 코드 확인하기

 

승인하면 다음과 비슷한 코드가 만들어집니다.

from app.db import create_connection
from app.repositories.inventory_repository import fetch_low_stock_products


def get_low_stock_report(connection):
    rows = fetch_low_stock_products(connection)

    report = []
    for row in rows:
        shortage_quantity = row["reorder_level"] - row["stock_quantity"]
        report.append({**row, "shortage_quantity": shortage_quantity})

    report.sort(key=lambda item: item["shortage_quantity"], reverse=True)
    return report


if __name__ == "__main__":
    connection = create_connection()
    try:
        for item in get_low_stock_report(connection):
            print(
                item["product_id"],
                item["product_name"],
                "재고", item["stock_quantity"],
                "기준", item["reorder_level"],
                "부족", item["shortage_quantity"],
            )
    finally:
        connection.close()

report.sort(key=..., reverse=True)shortage_quantity가 큰 값부터 정렬합니다. 부족 수량이 같은 상품이 여러 개면 원래 순서(product_id 오름차순)가 그대로 유지되는데, 이는 Python의 sort가 같은 값의 순서를 바꾸지 않는 성질(안정 정렬) 때문입니다. 이번 데이터에는 부족 수량이 같은 상품이 없어서 이 성질을 직접 확인할 일은 없지만, 알아 두면 이후 강의에서 정렬 기준이 여러 개로 늘어날 때 도움이 됩니다.

connection.close()finally에 두는 이유는, 출력 중 오류가 나더라도 연결이 닫히지 않은 채로 남지 않게 하기 위해서입니다.

▶ 지금 해보세요

  1. 위 요청을 입력하고 diff를 확인한 뒤 승인합니다.
  2. VS Code 통합 터미널에서 다음을 실행합니다.
python -m app.services.inventory_service

다음과 같은 결과가 출력되면 정상입니다.

6 웹캠 재고 3 기준 6 부족 3
3 USB-C 허브 재고 8 기준 10 부족 2

✔ 확인 기준: 웹캠(부족 3)이 첫 줄, USB-C 허브(부족 2)가 둘째 줄로 출력되고, 총 2건입니다.

 

7. 테스트로 확인하기

실제 DB 없이도 코드가 맞는지 확인하는 자동 확인 코드(테스트)를 만듭니다.

더보기

7.1 왜 테스트가 필요한가?

 

pip install pytest

 

6강에서 실행한 python -m app.services.inventory_service는 실제 DB에 연결해야만 실행됩니다. DB가 꺼져 있거나, 다른 사람이 데이터를 바꾸면 결과가 달라질 수 있습니다.

 

테스트는 실제 DB 대신 가짜 데이터를 넣어서, get_low_stock_report의 계산과 정렬 코드만 따로 확인하는 방법입니다. monkeypatch라는 기능으로 fetch_low_stock_products 함수를 가짜 함수로 잠깐 바꿔치기합니다.

 

 

7.2 테스트 코드 생성 요청하기

 

Claude Code 세션에 다음과 같이 요청합니다.

tests/test_inventory_service.py를 만들어줘.

조건:
- pytest와 monkeypatch를 사용한다.
- app.repositories.inventory_repository.fetch_low_stock_products를
  가짜 함수로 바꿔서 실제 DB에 연결하지 않는다.
- 테스트는 두 개만 만든다.
  1) 가짜 상품 두 개(부족 수량이 서로 다른 값)를 넣었을 때,
     부족 수량이 큰 상품이 먼저 오는지 확인하는 테스트
  2) 가짜 상품이 없을 때 결과가 빈 리스트인지 확인하는 테스트
- connection 인자는 실제로 쓰지 않으므로 None을 넘긴다.

diff로 보여주고 승인을 기다려줘.

 

 

 

7.3 완성된 테스트 코드 확인하기

 

승인하면 다음과 비슷한 코드가 만들어집니다.

from app.services import inventory_service


def test_shortage_큰_상품이_먼저_온다(monkeypatch):
    가짜_상품들 = [
        {"product_id": 3, "product_name": "USB-C 허브", "stock_quantity": 8, "reorder_level": 10},
        {"product_id": 6, "product_name": "웹캠", "stock_quantity": 3, "reorder_level": 6},
    ]

    def 가짜_조회(connection):
        return 가짜_상품들

    monkeypatch.setattr(
        inventory_service, "fetch_low_stock_products", 가짜_조회
    )

    결과 = inventory_service.get_low_stock_report(None)

    assert 결과[0]["product_id"] == 6
    assert 결과[0]["shortage_quantity"] == 3
    assert 결과[1]["product_id"] == 3
    assert 결과[1]["shortage_quantity"] == 2


def test_대상_상품이_없으면_빈_리스트(monkeypatch):
    def 가짜_조회(connection):
        return []

    monkeypatch.setattr(
        inventory_service, "fetch_low_stock_products", 가짜_조회
    )

    결과 = inventory_service.get_low_stock_report(None)

    assert 결과 == []

함수 이름과 변수 이름에 한글을 쓴 이유는, 이 강의에서 테스트 코드를 처음 접하는 학습자가 "무엇을 확인하는 테스트인가"를 코드만 보고도 알 수 있게 하기 위해서입니다. 실무에서는 영문 이름을 더 많이 쓰지만, 규칙을 어기는 것은 아닙니다.

 

 

7.4 pytest.ini 만들고 테스트 실행하기

 

프로젝트 최상위 폴더에 pytest.ini 파일을 다음 내용으로 만듭니다.

[pytest]
pythonpath = .

 

이 설정이 없으면 tests/ 폴더에서 app 패키지를 찾지 못해 ModuleNotFoundError가 발생합니다.

 

VS Code 통합 터미널에서 다음을 실행합니다.

pytest -v

 

다음과 같이 두 테스트가 모두 통과(PASSED)하면 정상입니다.

tests/test_inventory_service.py::test_shortage_큰_상품이_먼저_온다 PASSED
tests/test_inventory_service.py::test_대상_상품이_없으면_빈_리스트 PASSED

▶ 지금 해보세요

  1. 테스트 코드 생성을 요청하고 diff를 확인한 뒤 승인합니다.
  2. pytest.ini를 만듭니다.
  3. pytest -v를 실행합니다.

✔ 확인 기준: pytest -v 실행 결과에 테스트 2개가 모두 PASSED로 표시됩니다.

💡 팁: 테스트가 정상적으로 진행되지 않는다면, 소스코드 생성시 함수명과 같은 부분을 AI 가 임의로 생성하여 불일치하여 발생하는 문제이 경우가 높습니다.

 

8. MCP 조회 결과와 비교하기

→ 코드가 만든 결과와, 3~4강에서 사용한 읽기 전용 MCP 조회 결과가 같은지 비교합니다.

더보기

8.1 MCP로 같은 조건 조회하기

 

테스트가 통과했다고 해서 실제 DB에 대해서도 같은 결과가 나온다는 뜻은 아닙니다. 테스트는 가짜 데이터로 계산 로직만 확인한 것이고, 실제 DB 값과 맞는지는 별도로 확인해야 합니다. Claude Code 세션에 다음과 같이 요청합니다.

mysql-inventory MCP로 products 테이블에서
stock_quantity가 reorder_level 이하인 상품을 조회해줘.

조건:
- SELECT만 사용하고, 결과를 표로 보여줘.

내가 결과를 직접 확인할 것이므로, 결론을 먼저 단정하지 마.

 

[화면 캡처: MCP 조회 결과 표 — 상품 2건이 표시된 화면]

 

 

 

8.2 두 결과 비교하기

 

6.2에서 실행한 python -m app.services.inventory_service 결과와 8.1의 MCP 조회 결과를 비교합니다.

 

비교 항목 Python 코드 결과 MCP 조회 결과
건수 2건 2건
대상 상품 웹캠, USB-C 허브 웹캠, USB-C 허브

▶ 지금 해보세요

  1. MCP로 같은 조건을 조회합니다.
  2. 건수와 대상 상품이 Python 코드 결과와 같은지 표로 비교합니다.

✔ 확인 기준: Python 코드 결과와 MCP 조회 결과의 건수와 대상 상품이 정확히 일치합니다.

 

9. 오류 해결하기

→ 설정을 무작정 다시 만들지 않습니다. 다음 순서로 원인을 좁힙니다.

더보기

9.1 증상별 확인 순서

 

환경변수 확인 → 가상환경 활성화 확인 → pytest.ini 확인 → DB 계정 권한 확인

 

증상 먼저 확인할 항목 해결 방향
RuntimeError: INVENTORY_DB_PASSWORD 환경변수가 설정되지 않았습니다. 현재 쉘 프롬프트에서 export를 실행했는가 4.2의 read -s -p/export 명령을 같은 터미널 세션에서 다시 실행
ModuleNotFoundError: No module named 'app' pytest.ini가 프로젝트 최상위에 있는가 pythonpath = .가 포함된 pytest.ini를 최상위 폴더에 생성
ModuleNotFoundError: No module named 'mysql' 가상환경(.venv)이 활성화되어 있는가 source .venv/bin/activate 실행 후 pip install mysql-connector-python 재확인
Access denied for user 'inventory_app'@'...' 2강에서 만든 inventory_app 계정 비밀번호가 맞는가 비밀번호를 다시 입력하여 export, 계정 자체는 변경하지 않음
Python 코드 결과와 MCP 조회 결과의 건수가 다름 SQL 조건절이 5.1의 조건과 같은가 inventory_repository.pyWHERE 절을 schema.md 기준과 다시 대조

 

💡 팁: 계정 비밀번호가 기억나지 않는다고 해서 계정 권한을 넓히거나 새 계정을 만들지 않습니다. 2강에서 만든 inventory_app 계정을 그대로 사용합니다.

 

 

10. 이번 강의 완료 기준

→ 완성한 코드와 확인한 내용을 체크리스트로 정리합니다.

더보기

10.1 최종 체크리스트

 

☐ 조회 조건·정렬·결과 세 문장을 schema.md 컬럼 이름과 맞춰 확인했다

app/db.py가 생성되어 있고, 비밀번호는 환경변수로만 받는다

inventory_repository.py의 SQL 조건절이 stock_quantity <= reorder_level이다

python -m app.services.inventory_service 실행 결과가 웹캠(부족 3), USB-C 허브(부족 2) 순서로 2건 출력된다

pytest -v 실행 결과 테스트 2개가 모두 PASSED이다

☐ MCP 조회 결과와 Python 코드 결과의 건수·대상 상품이 일치한다

 

 

10.2 완성 구조

 

inventory-mysql-app/
├── app/
│   ├── __init__.py
│   ├── db.py
│   ├── repositories/
│   │   ├── __init__.py
│   │   └── inventory_repository.py
│   └── services/
│       ├── __init__.py
│       └── inventory_service.py
├── tests/
│   └── test_inventory_service.py
└── pytest.ini

 

 

10.3 이번 강의에서 아직 하지 않는 작업

 

이번 강의는 조회 결과를 문자로 출력하는 데까지만 다룹니다. 다음 작업은 아직 하지 않습니다.

  • 화면(PySide6)에 표로 보여주는 작업 (8강에서 진행)
  • 재고 수량을 바꾸는 작업(출고, UPDATE) — 이번 강의는 SELECT만 사용
  • 여러 조건을 동시에 거는 검색 기능

 

 

10.4 참고 문서

 

[OG 카드 자리: mysql-connector-python 공식 문서 — Connector/Python Developer Guide]

pytest의 monkeypatch 사용법은 pytest 공식 문서의 "How to monkeypatch/mock modules and environments" 페이지에서 확인할 수 있습니다.

→ 다음 강의 (8강): 이번 강의에서 만든 inventory_service.py를 그대로 사용해, PySide6 화면에 재고 부족 상품을 표로 보여줍니다.

 

11. 실습 과제

→ 조건을 바꿔 보면서 조회·정렬·테스트 흐름을 스스로 반복합니다.

더보기

11.1 정렬 기준 바꿔 보기

 

Claude Code에 "부족 수량이 아니라 product_id 오름차순으로 정렬해줘"라고 요청하고, diff로 inventory_service.py가 어떻게 바뀌는지 확인합니다. 확인 후에는 다시 부족 수량 기준으로 되돌립니다.

 

 

11.2 테스트 케이스 추가하기

 

가짜 상품 데이터를 3개로 늘려 test_inventory_service.py에 테스트를 하나 더 추가합니다. Claude Code에 요청할 때도 diff로 검토한 뒤 승인합니다.

 

 

11.3 제출물

 

다음 세 가지를 캡처하거나 정리하여 제출합니다.

  • pytest -v 실행 결과 (기존 2개 + 추가한 테스트 모두 PASSED)
  • 11.1에서 정렬 기준을 바꿨다가 되돌린 diff 화면 캡처 2장(변경 시점, 원복 시점)
  • Python 코드 결과와 MCP 조회 결과 비교표(8.2 형식)