Skip to content

shared-moon/realex-question

Repository files navigation

야채가게 (Vegetable Shop) - Kotlin + Spock 학습 예제

📖 프로젝트 소개

이 프로젝트는 TDD 학습을 위한 Kotlin + Spock 예제입니다.

  • 목적: Spock 테스트를 먼저 보고, 그 테스트를 통과하도록 Kotlin 코드를 구현하는 연습
  • 도메인: 야채가게 (상품 등록, 조회, 재고 관리, 판매)
  • 핵심: 비즈니스 로직과 UI를 분리하여 테스트 가능하도록 설계
  • 테스트: Groovy 기반 Spock으로 given/when/then 스타일의 명확한 시나리오 테스트

🏗️ 프로젝트 구조

realex-question/
├── src/
│   ├── main/kotlin/vegetableshop/
│   │   ├── domain/
│   │   │   └── Product.kt              # 상품 도메인 모델
│   │   ├── repository/
│   │   │   └── Inventory.kt            # 재고 저장소
│   │   ├── service/
│   │   │   └── ShopService.kt          # 판매 비즈니스 로직
│   │   └── Main.kt                     # 콘솔 UI
│   └── test/groovy/vegetableshop/
│       ├── domain/
│       │   └── ProductSpec.groovy      # Product 테스트 (24개 테스트)
│       ├── repository/
│       │   └── InventorySpec.groovy    # Inventory 테스트 (8개 테스트)
│       └── service/
│           └── ShopServiceSpec.groovy  # ShopService 테스트 (12개 테스트)
├── build.gradle.kts                     # Gradle 빌드 설정
└── settings.gradle.kts

🚀 빌드 및 실행

1. 테스트 실행 (권장 - 학습용)

# 모든 Spock 테스트 실행
./gradlew test

# 테스트 결과 확인
# build/reports/tests/test/index.html 파일을 브라우저로 열기

2. 프로그램 실행

# 애플리케이션 실행
./gradlew run --console=plain

# 또는 JAR 빌드 후 실행
./gradlew build
java -jar build/libs/realex-question-1.0-SNAPSHOT.jar

3. Main 함수 직접 실행 (IntelliJ IDEA)

  1. src/main/kotlin/vegetableshop/Main.kt 파일을 엽니다
  2. main() 함수 옆의 실행 버튼을 클릭합니다

📚 기능 요구사항

1. 상품 등록

  • 품목 이름, 단가, 재고 수량을 등록
  • 중복된 이름의 상품 등록 시 실패

2. 상품 조회

  • 모든 상품 리스트 반환
  • 재고가 0이어도 조회 가능

3. 재고 추가

  • 기존 상품의 재고 수량 증가
  • 존재하지 않는 상품에 대한 재고 추가 시 예외 발생

4. 판매(구매)

  • 재고가 충분하면 재고 차감 및 총 가격 반환
  • 재고 부족 또는 없는 상품일 경우 실패

🧪 테스트 구조

ProductSpec.groovy (도메인 모델 테스트)

  • 생성 테스트 (유효성 검증)
  • 재고 추가/차감 테스트
  • 가격 계산 테스트
  • Data class 동작 테스트 (equals, hashCode, copy)

InventorySpec.groovy (저장소 테스트)

  • 상품 등록 테스트 (중복 체크)
  • 상품 조회 테스트
  • 재고 추가/차감 테스트

ShopServiceSpec.groovy (비즈니스 로직 테스트)

  • 상품 등록/조회 테스트
  • 재고 추가 테스트
  • 판매 테스트 (재고 충분/부족/없는 상품)
  • 통합 시나리오 테스트

💡 학습 포인트

1. 테스트 주도 학습 (Test-Driven Learning)

// Spock의 given/when/then 패턴으로 명확한 시나리오 작성
def "재고가 충분하면 판매가 성공한다"() {
    given: "재고가 50개인 양파(단가 2000원)가 등록되어 있을 때"
    shopService.registerProduct("양파", 2000, 50)

    when: "20개를 판매하면"
    def result = shopService.sellProduct("양파", 20)

    then: "판매가 성공한다"
    result.success == true
    result.totalPrice == 40000
}

2. 관심사의 분리 (Separation of Concerns)

  • Domain: 비즈니스 규칙 (Product)
  • Repository: 데이터 관리 (Inventory)
  • Service: 비즈니스 로직 (ShopService)
  • UI: 사용자 인터페이스 (Main, VegetableShopApp)

3. Kotlin과 Groovy의 상호운용성

  • Kotlin으로 작성된 코드를 Groovy 기반 Spock으로 테스트
  • JVM 기반 언어의 강력한 통합

🔧 기술 스택

  • Kotlin: 2.2.10
  • Gradle: 8.14
  • Spock: 2.3-groovy-4.0
  • Groovy: 4.0.23
  • Java: 21

📝 콘솔 UI 예시

=== 야채가게에 오신 것을 환영합니다 ===

---------- 메뉴 ----------
1. 상품 등록
2. 상품 목록 보기
3. 재고 추가
4. 상품 판매
5. 종료
선택: 2

---------- 상품 목록 ----------
상품명                단가(원)        재고
----------------------------------------
양파                  2,000          50
감자                  3,000          30
당근                  1,500          40

---------- 메뉴 ----------
1. 상품 등록
2. 상품 목록 보기
3. 재고 추가
4. 상품 판매
5. 종료
선택: 4

상품명: 양파
구매 수량: 10
✓ 판매가 완료되었습니다
  - 상품: 양파
  - 수량: 10
  - 총 금액: 20,000원
  - 남은 재고: 40

🎯 학습 방법 제안

  1. 테스트 먼저 읽기: src/test/groovy/ 디렉토리의 테스트 코드를 먼저 읽어보세요
  2. 구현 확인: 테스트가 어떻게 통과되는지 src/main/kotlin/ 코드를 확인하세요
  3. 테스트 실행: ./gradlew test로 모든 테스트가 통과하는지 확인하세요
  4. 기능 추가 연습: 새로운 기능을 테스트부터 작성하고 구현해보세요
    • 예: 할인 기능, 카테고리 분류, 유통기한 관리 등

📊 테스트 결과

./gradlew test

BUILD SUCCESSFUL in 3s

34 tests completed ✓
- ProductSpec: 14개 테스트
- InventorySpec: 8개 테스트
- ShopServiceSpec: 12개 테스트

🤝 기여 및 학습

이 프로젝트는 학습 목적으로 만들어졌습니다. 자유롭게 수정하고 확장해보세요!

추가 학습 아이디어

  • 할인 정책 추가 (정률, 정액 할인)
  • 주문 내역 관리 (Order 도메인)
  • 회원 시스템 (Member 도메인)
  • 데이터베이스 연동 (H2, PostgreSQL)
  • REST API 추가 (Spring Boot)

Happy Testing with Kotlin + Spock! 🎉

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published