Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.gradle
build
.idea
*.iml
.git
.gitignore
.DS_Store
docs
*.md
10 changes: 10 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM eclipse-temurin:21-jdk AS builder
WORKDIR /app
COPY . .
RUN ./gradlew bootJar --no-daemon

FROM eclipse-temurin:21-jre-alpine
RUN apk add --no-cache curl
WORKDIR /app
COPY --from=builder /app/build/libs/*.jar app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
25 changes: 24 additions & 1 deletion README.md

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

테스트 실행 구조: 테스트 코드는 호스트 JVM에서, 앱/DB는 Docker 컨테이너에서 실행하는 구조입니다. 테스트까지 컨테이너에 넣는 방식과 비교했을 때 현재 구조가 적절한지 피드백 부탁드립니다.

테스트까지 컨테이너에 넣는 방식의 장점에 대해서 고민해보면 좋을 것 같아요. 현재는 별도로 호출해도 되는 환경이지만 다른 사람의 환경, ci의 환경 모두 다른 환경에서 테스트 호출이 실패하는 경우를 가정한다면 가능하면 모두 docker 컨테이너 안에서 실행이 될 수 있도록 구성하는 것도 좋을 것 같네요 :)

Original file line number Diff line number Diff line change
@@ -1 +1,24 @@
# spring-gift-test
# spring-gift-test

## 사전 요구사항

- Java 21
- Docker (Cucumber 테스트 실행 시 필요)

## 테스트 실행 방법

### 기존 인수 테스트 (H2)
```bash
./gradlew test
```
RestAssured 인수 테스트 3개를 H2 인메모리 DB로 실행합니다.

### Cucumber 테스트 (Docker 환경)
```bash
./gradlew cucumberTest
```
Docker Compose로 PostgreSQL + 애플리케이션 컨테이너를 자동 시작하고, Cucumber 시나리오 8개를 실행한 후 컨테이너를 자동 종료합니다.

### Cucumber 시나리오 구조
- 시나리오 정의: `src/test/resources/features/*.feature`
- Step 구현: `src/test/java/gift/acceptance/cucumber/`
35 changes: 34 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,43 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'org.postgresql:postgresql'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.rest-assured:rest-assured'
testImplementation platform('io.cucumber:cucumber-bom:7.22.0')
testImplementation 'io.cucumber:cucumber-java'
testImplementation 'io.cucumber:cucumber-spring'
testImplementation 'io.cucumber:cucumber-junit-platform-engine'
testImplementation 'org.junit.platform:junit-platform-suite'
}

tasks.named('test') {
useJUnitPlatform()
useJUnitPlatform {
excludeEngines 'cucumber'
}
exclude '**/CucumberSuite*'
}

tasks.register('dockerBuild', Exec) {
commandLine 'docker-compose', 'build'
}

tasks.register('dockerUp', Exec) {
dependsOn 'dockerBuild'
commandLine 'docker-compose', 'up', '-d', '--wait'
}

tasks.register('dockerDown', Exec) {
commandLine 'docker-compose', 'down', '-v'
}

tasks.register('cucumberTest', Test) {
useJUnitPlatform {
includeEngines 'cucumber'
}
systemProperty 'cucumber.glue', 'gift.acceptance.cucumber'
systemProperty 'cucumber.features', 'classpath:features'
systemProperty 'cucumber.plugin', 'pretty'
dependsOn 'dockerUp'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

명령어 하나만 실행해도 모두 동작할 수 있도록 잘 구성해주셨네요 👍

finalizedBy 'dockerDown'
}
34 changes: 34 additions & 0 deletions docker-compose.yml

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

한번에 전체 스택을 관리하기보다는 infra영역과 어플리케이션 영역을 분리해볼수도 있을 것 같네요.

msa 환경이나 여러 infra 환경이 있다라는 것을 가정한다면, 이후에 docker-compose.yml을 관리하기 힘들어질 수 있고 각 목적에 따라 분리했을때의 장점도 고민 포인트가 될 수 있을 것 같아요.

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
services:
postgres:
image: postgres:17-alpine
environment:
POSTGRES_DB: gift_test
POSTGRES_USER: test
POSTGRES_PASSWORD: test
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U test -d gift_test"]
interval: 3s
timeout: 3s
retries: 5

app:
build: .
ports:
- "28080:8080"
depends_on:
postgres:
condition: service_healthy
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/gift_test
SPRING_DATASOURCE_USERNAME: test
SPRING_DATASOURCE_PASSWORD: test
SPRING_JPA_HIBERNATE_DDL_AUTO: create
SPRING_JPA_DATABASE_PLATFORM: org.hibernate.dialect.PostgreSQLDialect
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/api/categories || exit 1"]
interval: 5s
timeout: 3s
retries: 10
start_period: 30s
6 changes: 3 additions & 3 deletions docs/ANALYSIS.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,11 @@ public class Gift {

| 메서드 | 경로 | 설명 | 요청 바디 |
|--------|------|------|----------|
| POST | `/api/categories` | 카테고리 생성 | `{ "name": "..." }` |
| POST | `/api/categories` | 카테고리 생성 | JSON `{ "name": "..." }` |
| GET | `/api/categories` | 카테고리 목록 조회 | - |
| POST | `/api/products` | 상품 등록 | `{ "name", "price", "imageUrl", "categoryId" }` |
| POST | `/api/products` | 상품 등록 | JSON `{ "name", "price", "imageUrl", "categoryId" }` |
| GET | `/api/products` | 상품 목록 조회 | - |
| POST | `/api/gifts` | 선물 전달 | `{ "optionId", "quantity", "receiverId", "message" }` |
| POST | `/api/gifts` | 선물 전달 | JSON `{ "optionId", "quantity", "receiverId", "message" }` |

### 선물 전달 API 상세

Expand Down
Loading