src/test/java/com/scraping/agent/
├── domain/
│ ├── news/
│ │ ├── service/
│ │ │ └── NewsServiceTest.java # 단위 테스트 (Mockito)
│ │ └── repository/
│ │ └── NewsItemRepositoryTest.java # DB 통합 테스트
│ └── notes/
│ └── service/
│ └── PostServiceTest.java
└── global/
└── health/
└── HealthControllerTest.java # Controller 슬라이스 테스트
단위 테스트 (Service)
@ExtendWith(MockitoExtension.class)
class PostServiceTest {
@Mock
private PostRepository postRepository;
@InjectMocks
private PostService postService;
@Test
@DisplayName("포스트 등록 성공")
void regPost_success() {
// Given
PostCreateReq req = new PostCreateReq("제목", "내용", "BACKEND");
Post savedPost = Post.builder()
.title("제목").content("내용").category("BACKEND").build();
given(postRepository.save(any())).willReturn(savedPost);
// When
PostDetailRes result = postService.regPost(req);
// Then
assertThat(result.getTitle()).isEqualTo("제목");
verify(postRepository).save(any(Post.class));
}
@Test
@DisplayName("존재하지 않는 포스트 조회 시 예외 발생")
void getPost_notFound_throwsException() {
// Given
Long nonExistentId = 999L;
given(postRepository.findById(nonExistentId)).willReturn(Optional.empty());
// When & Then
assertThatThrownBy(() -> postService.getPost(nonExistentId))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("찾을 수 없습니다");
}
}
Repository 통합 테스트
@DataJpaTest
@ActiveProfiles("test")
class PostRepositoryTest {
@Autowired
private PostRepository postRepository;
@Autowired
private TestEntityManager em;
@Test
@DisplayName("제목 중복 여부 확인")
void existsByTitle_duplicate() {
// Given
Post post = Post.builder().title("중복 제목").content("내용").category("BACKEND").build();
em.persist(post);
em.flush();
// When
boolean exists = postRepository.existsByTitle("중복 제목");
// Then
assertThat(exists).isTrue();
}
}
Controller 슬라이스 테스트
@WebMvcTest(NotesController.class)
class NotesControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private PostService postService;
@Test
@DisplayName("노트 목록 페이지 200 반환")
void notesList_returnsOk() throws Exception {
// Given
given(postService.getPostPage(anyInt(), any())).willReturn(Page.empty());
// When & Then
mockMvc.perform(get("/notes")
.param("page", "0"))
.andExpect(status().isOk())
.andExpect(view().name("notes/list"));
}
@Test
@DisplayName("REST API 노트 등록 201 반환")
void regPost_returnsCreated() throws Exception {
String body = """
{"title": "테스트", "content": "내용", "category": "BACKEND"}
""";
PostDetailRes res = new PostDetailRes(1L, "테스트", "내용", "BACKEND", LocalDateTime.now());
given(postService.regPost(any())).willReturn(res);
mockMvc.perform(post("/api/v1/posts")
.contentType(MediaType.APPLICATION_JSON)
.content(body))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.data.title").value("테스트"));
}
}