스프링 전환 계획 수립 (iss-cb35afc33813)
This commit is contained in:
parent
ca3df20649
commit
542254408c
1 changed files with 159 additions and 0 deletions
159
spring-transition-plan/test_reference.md
Normal file
159
spring-transition-plan/test_reference.md
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
# 스프링 전환 테스트 참조 문서
|
||||||
|
|
||||||
|
## 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<User> 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<User> 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 패턴 적용
|
||||||
Loading…
Add table
Add a link
Reference in a new issue