-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
documentationImprovements or additions to documentationImprovements or additions to documentation
Milestone
Description
Labels: testing, quality, high-priority
Milestone: Quality & Documentation
Assignee: @al1kite
목적
전체 플로우를 E2E로 검증
테스트 대상
1. 정상 플로우
@SpringBootTest(webEnvironment = RANDOM_PORT)
@AutoConfigureMockMvc
class AnalysisIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
void fullFlow_success() throws Exception {
// 1. 파일 업로드 (분석 요청)
var file = new MockMultipartFile(
"file",
"test.csv",
"text/csv",
createValidCsvContent().getBytes()
);
var result = mockMvc.perform(
multipart("/api/analysis")
.file(file))
.andExpect(status().isCreated()) // 201
.andExpect(header().exists("Location"))
.andExpect(jsonPath("$.analysisId").exists())
.andReturn();
var response = objectMapper.readValue(
result.getResponse().getContentAsString(),
AnalysisIdResponse.class
);
var analysisId = response.analysisId();
// 2. 결과 조회
mockMvc.perform(get("/api/analysis/" + analysisId))
.andExpect(status().isOk())
.andExpect(jsonPath("$.analysisId").value(analysisId))
.andExpect(jsonPath("$.basicStats.totalRequests").value(1000))
.andExpect(jsonPath("$.topStats.topIps").isArray())
.andExpect(jsonPath("$.ipDetails").isNotEmpty());
// 3. 전체 목록 조회
mockMvc.perform(get("/api/analysis"))
.andExpect(status().isOk())
.andExpect(jsonPath("$").isArray())
.andExpect(jsonPath("$[0].analysisId").value(analysisId));
// 4. 삭제
mockMvc.perform(delete("/api/analysis/" + analysisId))
.andExpect(status().isNoContent()); // 204
// 5. 삭제 확인
mockMvc.perform(get("/api/analysis/" + analysisId))
.andExpect(status().isNotFound()); // 404
}
}2. 에러 케이스
@Test
void invalidFile_returns400() throws Exception {
var file = new MockMultipartFile(
"file",
"test.txt",
"text/plain",
"not a csv".getBytes()
);
mockMvc.perform(multipart("/api/analysis").file(file))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.errorCode").value("INVALID_FILE"))
.andExpect(jsonPath("$.errorId").exists());
}
@Test
void fileTooLarge_returns413() throws Exception {
var largeContent = new byte[60 * 1024 * 1024]; // 60MB
var file = new MockMultipartFile("file", "large.csv", "text/csv", largeContent);
mockMvc.perform(multipart("/api/analysis").file(file))
.andExpect(status().isPayloadTooLarge())
.andExpect(jsonPath("$.errorCode").value("FILE_TOO_LARGE"))
.andExpect(jsonPath("$.details.fileSizeMB").value(60));
}
@Test
void rateLimit_returns429() throws Exception {
var file = createValidFile();
// 10번 성공
for (int i = 0; i < 10; i++) {
mockMvc.perform(multipart("/api/analysis").file(file))
.andExpect(status().isCreated());
}
// 11번째 실패
mockMvc.perform(multipart("/api/analysis").file(file))
.andExpect(status().isTooManyRequests())
.andExpect(header().exists("Retry-After"));
}3. 캐싱 테스트
@Test
void getResult_withETag_returns304() throws Exception {
var analysisId = createAnalysis();
// 첫 요청
var firstResult = mockMvc.perform(get("/api/analysis/" + analysisId))
.andExpect(status().isOk())
.andExpect(header().exists("ETag"))
.andReturn();
var etag = firstResult.getResponse().getHeader("ETag");
// If-None-Match로 재요청
mockMvc.perform(get("/api/analysis/" + analysisId)
.header("If-None-Match", etag))
.andExpect(status().isNotModified()) // 304
.andExpect(header().exists("ETag"))
.andExpect(content().string("")); // body 없음
}4. 동시성 테스트
@Test
void concurrentRequests_allSucceed() throws Exception {
var executor = Executors.newFixedThreadPool(10);
var files = IntStream.range(0, 20)
.mapToObj(i -> createValidFile())
.toList();
var futures = files.stream()
.map(file -> CompletableFuture.runAsync(() -> {
try {
mockMvc.perform(multipart("/api/analysis").file(file))
.andExpect(status().isCreated());
} catch (Exception e) {
throw new RuntimeException(e);
}
}, executor))
.toList();
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.get(10, TimeUnit.SECONDS);
// 모두 성공
assertThat(futures).allMatch(f -> !f.isCompletedExceptionally());
}작업 내용
- 정상 플로우 통합 테스트
- 에러 케이스 테스트 (400, 404, 413, 429, 500)
- 캐싱 테스트 (ETag, 304)
- 동시성 테스트
- 성능 테스트 (대용량 파일)
- 테스트 커버리지 80% 이상
의존성
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.testcontainers:testcontainers:1.19.0") // 선택완료 조건
- 모든 API 엔드포인트 테스트
- 모든 에러 케이스 커버
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
documentationImprovements or additions to documentationImprovements or additions to documentation