# 스프링 전환 테스트 참조 문서 ## 1. 테스트 전략 개요 ### 1.1 테스트 피라미드 ``` ▲ /E2E\ (End-to-End) /──────\ /Integration\ (Integration) /────────────\ / Unit Tests \ (Unit) /────────────────\ ``` ### 1.2 목표 커버리지 | 테스트 유형 | 목표 | 도구 | |------------|------|------| | 단위 테스트 | 80% | JUnit 5, Mockito | | 통합 테스트 | 70% | Spring Test, TestContainers | | E2E 테스트 | 50% | RestAssured | ## 2. 단위 테스트 기준 ### 2.1 Service Layer 테스트 ```java @SpringBootTest class UserServiceTest { @Autowired private UserService userService; @MockBean private UserRepository userRepository; @Test void shouldCreateUserSuccessfully() { // Given UserDto dto = new UserDto("test@example.com", "password"); when(userRepository.save(any(User.class))).thenAnswer(i -> i.getArgument(0)); // When User result = userService.createUser(dto); // Then assertThat(result.getEmail()).isEqualTo("test@example.com"); verify(userRepository).save(any(User.class)); } @Test void shouldThrowExceptionForDuplicateEmail() { // Given String email = "existing@example.com"; when(userRepository.findByEmail(email)).thenReturn(Optional.of(new User())); // When/Then assertThatThrownBy(() -> userService.createUser(new UserDto(email, "pass"))) .isInstanceOf(DuplicateEmailException.class); } } ``` ### 2.2 Repository 테스트 ```java @DataJpaTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) class UserRepositoryTest { @Autowired private UserRepository userRepository; @Autowired private TestEntityManager entityManager; @Test void shouldFindByEmail() { // Given User user = new User("test@example.com", "encoded"); entityManager.persist(user); // When Optional found = userRepository.findByEmail("test@example.com"); // Then assertThat(found).isPresent(); } } ``` ### 2.3 Controller 테스트 ```java @WebMvcTest(UserController.class) class UserControllerTest { @Autowired private MockMvc mockMvc; @MockBean private UserService userService; @Test void shouldCreateUser() throws Exception { // Given CreateUserRequest request = new CreateUserRequest("test@example.com", "password"); when(userService.createUser(any())).thenReturn(new User(1L, "test@example.com")); // When/Then mockMvc.perform(post("/api/users") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(status().isCreated()) .andExpect(jsonPath("$.email").value("test@example.com")); } } ``` ## 3. 통합 테스트 기준 ### 3.1 Database Integration Test ```java @SpringBootTest @Testcontainers @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) class UserRepositoryIntegrationTest { @Container static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:15"); @DynamicPropertySource static void properties(DynamicPropertyRegistry registry) { registry.add("spring.datasource.url", postgres::getJdbcUrl); registry.add("spring.datasource.username", postgres::getUsername); registry.add("spring.datasource.password", postgres::getPassword); } @Test void shouldPersistAndRetrieveUser() { User user = new User("integration@test.com", "password"); User saved = userRepository.save(user); Optional found = userRepository.findById(saved.getId()); assertThat(found).isPresent(); } } ``` ## 4. 테스트 실행 기준 | 테스트 유형 | 실행 시점 | 실패 시 동작 | |-----------|----------|-------------| | 단위 테스트 | 매 커밋 | 빌드 실패 | | 통합 테스트 | PR 생성 | 빌드 실패 | | E2E 테스트 | 일 1회 | 알림 발송 | | 성능 테스트 | 주 1회 | 보고 | ## 5. 검증 체크리스트 ### 전환 완료 기준 - [ ] 단위 테스트 커버리지 80% 이상 - [ ] 모든 Service 메서드 테스트 coverage - [ ] 모든 Repository 쿼리 테스트 coverage - [ ] 모든 Controller endpoint 테스트 coverage - [ ] Integration Test Database 환경 독립적 실행 - [ ] Mock 객체 주입 검증 - [ ] 예외 처리 경로 테스트 coverage - [ ] 테스트 격리 확인 ### 코드 품질 기준 - [ ] SonarQube Quality Gate 통과 - [ ] Cyclomatic Complexity < 10 - [ ] 테스트 명명 규칙 준수 - [ ] Given-When-Then 패턴 적용