From 8652e936e8e67f26dd8aa0b849dec6a6279947e5 Mon Sep 17 00:00:00 2001 From: Chaemin Yu Date: Sun, 3 Aug 2025 02:05:20 +0900 Subject: [PATCH 1/6] test: record API --- .../service/StudyRecordServiceTest.java | 287 ++++++++++++++++++ 1 file changed, 287 insertions(+) create mode 100644 src/test/java/org/example/studylog/service/StudyRecordServiceTest.java diff --git a/src/test/java/org/example/studylog/service/StudyRecordServiceTest.java b/src/test/java/org/example/studylog/service/StudyRecordServiceTest.java new file mode 100644 index 0000000..7db4331 --- /dev/null +++ b/src/test/java/org/example/studylog/service/StudyRecordServiceTest.java @@ -0,0 +1,287 @@ +package org.example.studylog.service; + +import org.example.studylog.dto.studyrecord.*; +import org.example.studylog.entity.Streak; +import org.example.studylog.entity.StudyRecord; +import org.example.studylog.entity.category.Category; +import org.example.studylog.entity.category.Color; +import org.example.studylog.entity.user.Role; +import org.example.studylog.entity.user.User; +import org.example.studylog.repository.CategoryRepository; +import org.example.studylog.repository.StreakRepository; +import org.example.studylog.repository.StudyRecordRepository; +import org.example.studylog.repository.UserRepository; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@SpringBootTest +@Transactional +class StudyRecordServiceTest { + + @Autowired + private StudyRecordService studyRecordService; + @Autowired + private UserRepository userRepository; + @Autowired + private CategoryRepository categoryRepository; + @Autowired + private StudyRecordRepository studyRecordRepository; + @Autowired + private StreakRepository streakRepository; + + // === 1. 데이터 무결성 테스트 === + + @Test + @DisplayName("기록 생성 중 카테고리가 삭제되는 경우") + void createRecord_CategoryDeletedDuringCreation_ShouldFail() { + // Given + User user = createTestUser(); + Category category = createTestCategory(user); + CreateStudyRecordRequestDTO requestDTO = createValidRequestDTO(category.getId()); + + // 다른 스레드에서 카테고리 삭제 시뮬레이션 + CompletableFuture.runAsync(() -> { + categoryRepository.delete(category); + categoryRepository.flush(); + }); + + // When & Then + assertThrows(IllegalArgumentException.class, + () -> studyRecordService.createStudyRecord(user, requestDTO)); + } + + @Test + @DisplayName("기록 생성 시 제목 길이 경계값 테스트") + @ParameterizedTest + @ValueSource(ints = {0, 1, 19, 20, 21, 50}) + void createRecord_TitleLengthBoundary(int titleLength) { + // Given + User user = createTestUser(); + Category category = createTestCategory(user); + + CreateStudyRecordRequestDTO requestDTO = new CreateStudyRecordRequestDTO(); + requestDTO.setCategoryId(category.getId()); + requestDTO.setTitle("a".repeat(titleLength)); + requestDTO.setContent("유효한 내용입니다. 최소 10자 이상 작성"); + + // When & Then + if (titleLength == 0 || titleLength > 20) { + assertThrows(Exception.class, + () -> studyRecordService.createStudyRecord(user, requestDTO)); + } else { + assertDoesNotThrow( + () -> studyRecordService.createStudyRecord(user, requestDTO)); + } + } + + @Test + @DisplayName("기록 내용에 특수 문자 및 이모지 포함") + void createRecord_SpecialCharactersAndEmojis() { + // Given + User user = createTestUser(); + Category category = createTestCategory(user); + + String specialContent = "특수문자 테스트 !@#$%^&*()_+ 이모지 테스트 😀🎉📚 " + + "HTML 태그 " + + "SQL 문자 '; DROP TABLE study_record; --"; + + CreateStudyRecordRequestDTO requestDTO = new CreateStudyRecordRequestDTO(); + requestDTO.setCategoryId(category.getId()); + requestDTO.setTitle("특수문자 테스트"); + requestDTO.setContent(specialContent); + + // When + CreateStudyRecordResponseDTO result = studyRecordService.createStudyRecord(user, requestDTO); + + // Then + assertThat(result.getRecord().getContent()).contains("특수문자 테스트"); + // XSS 공격 문자열이 그대로 저장되지 않았는지 확인 + assertThat(result.getRecord().getContent()).doesNotContain("