From 100e482fde93ccc38d72b8c03b32f791544ac42e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=82=98=EA=B2=BD=ED=98=B8?= Date: Tue, 3 Sep 2024 00:48:02 +0900 Subject: [PATCH 1/2] =?UTF-8?q?test:=20mock=20test=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. @SpringBootTest, TestContainer 의존성 제거 2. 불필요한 Mock 객체 제거 --- .../answer/application/AnswerManagerTest.java | 14 +- .../mju/iphak/maru_egg/common/MockTest.java | 6 - .../QuestionProcessingServiceTest.java | 138 +++++++++++------- .../application/QuestionServiceTest.java | 71 ++++----- .../QuestionTypeStatusServiceTest.java | 15 +- 5 files changed, 133 insertions(+), 111 deletions(-) diff --git a/src/test/java/mju/iphak/maru_egg/answer/application/AnswerManagerTest.java b/src/test/java/mju/iphak/maru_egg/answer/application/AnswerManagerTest.java index 45555a4..f725b24 100644 --- a/src/test/java/mju/iphak/maru_egg/answer/application/AnswerManagerTest.java +++ b/src/test/java/mju/iphak/maru_egg/answer/application/AnswerManagerTest.java @@ -16,24 +16,14 @@ import jakarta.persistence.EntityNotFoundException; import mju.iphak.maru_egg.answer.domain.Answer; import mju.iphak.maru_egg.answer.dto.request.CreateAnswerRequest; -import mju.iphak.maru_egg.answer.repository.AnswerReferenceRepository; import mju.iphak.maru_egg.answer.repository.AnswerRepository; +import mju.iphak.maru_egg.common.MockTest; import mju.iphak.maru_egg.question.domain.Question; import mju.iphak.maru_egg.question.domain.QuestionCategory; import mju.iphak.maru_egg.question.domain.QuestionType; import mju.iphak.maru_egg.question.dto.request.CreateQuestionRequest; -import mju.iphak.maru_egg.question.repository.QuestionRepository; -public class AnswerManagerTest { - - @Mock - private QuestionRepository questionRepository; - - @Mock - private AnswerApiClient answerApiClient; - - @Mock - private AnswerReferenceRepository answerReferenceRepository; +public class AnswerManagerTest extends MockTest { @Mock private AnswerRepository answerRepository; diff --git a/src/test/java/mju/iphak/maru_egg/common/MockTest.java b/src/test/java/mju/iphak/maru_egg/common/MockTest.java index 310ec70..be9290a 100644 --- a/src/test/java/mju/iphak/maru_egg/common/MockTest.java +++ b/src/test/java/mju/iphak/maru_egg/common/MockTest.java @@ -3,15 +3,9 @@ import org.junit.Ignore; import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Import; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.TestPropertySource; -import mju.iphak.maru_egg.TestcontainersConfiguration; - -@Import(TestcontainersConfiguration.class) -@SpringBootTest @ActiveProfiles("test") @RunWith(MockitoJUnitRunner.class) @TestPropertySource(properties = { diff --git a/src/test/java/mju/iphak/maru_egg/question/application/QuestionProcessingServiceTest.java b/src/test/java/mju/iphak/maru_egg/question/application/QuestionProcessingServiceTest.java index 3450698..900e639 100644 --- a/src/test/java/mju/iphak/maru_egg/question/application/QuestionProcessingServiceTest.java +++ b/src/test/java/mju/iphak/maru_egg/question/application/QuestionProcessingServiceTest.java @@ -1,6 +1,7 @@ package mju.iphak.maru_egg.question.application; import static org.assertj.core.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; @@ -24,6 +25,7 @@ import com.google.gson.Gson; +import jakarta.persistence.EntityNotFoundException; import mju.iphak.maru_egg.answer.application.AnswerApiClient; import mju.iphak.maru_egg.answer.application.AnswerManager; import mju.iphak.maru_egg.answer.domain.Answer; @@ -32,7 +34,6 @@ import mju.iphak.maru_egg.answer.dto.response.AnswerReferenceResponse; import mju.iphak.maru_egg.answer.dto.response.AnswerResponse; import mju.iphak.maru_egg.answer.dto.response.LLMAnswerResponse; -import mju.iphak.maru_egg.answer.repository.AnswerReferenceRepository; import mju.iphak.maru_egg.answer.repository.AnswerRepository; import mju.iphak.maru_egg.common.MockTest; import mju.iphak.maru_egg.common.utils.PhraseExtractionUtils; @@ -53,9 +54,6 @@ class QuestionProcessingServiceTest extends MockTest { @Mock private AnswerRepository answerRepository; - @Mock - private AnswerReferenceRepository answerReferenceRepository; - @Mock private AnswerManager answerManager; @@ -76,7 +74,6 @@ void setUp() { setupMockEntities(); setupMockServer(); setupAnswerManagerMock(); - questionProcessingService = new QuestionProcessingService(questionRepository, answerManager); } @AfterEach @@ -86,55 +83,6 @@ void shutdown() throws IOException { } } - private void setupMockEntities() { - question = mock(Question.class); - answer = mock(Answer.class); - references = List.of(AnswerReference.of("테스트 title", "테스트 link", answer)); - - when(question.getId()).thenReturn(1L); - when(answer.getId()).thenReturn(1L); - when(answer.getReferences()).thenReturn(references); - - when(answerManager.getAnswerByQuestionId(1L)).thenReturn(answer); - when(answerRepository.findByQuestionId(anyLong())).thenReturn(Optional.of(answer)); - - when(questionRepository.searchQuestionsByContentTokenAndTypeAndCategory(anyString(), any(QuestionType.class), - any(QuestionCategory.class))) - .thenReturn(Optional.of(List.of(QuestionCore.of(1L, "테스트 질문입니다.")))); - when(questionRepository.findById(1L)).thenReturn(Optional.of(question)); - } - - private void setupMockServer() { - this.mockWebServer = new MockWebServer(); - answerApiClient = new AnswerApiClient(WebClient.builder() - .baseUrl(this.mockWebServer.url("/").toString()) - .clientConnector(new ReactorClientHttpConnector()) - .build()); - } - - private void setupAnswerManagerMock() { - when(answerManager.getAnswerByQuestionId(anyLong())).thenReturn(answer); - } - - private LLMAnswerResponse mockAskQuestion(LLMAskQuestionRequest request) { - MultiValueMap formData = new LinkedMultiValueMap<>(); - formData.add("questionType", request.questionType()); - formData.add("questionCategory", request.questionCategory()); - formData.add("question", request.question()); - - List references = List.of(AnswerReferenceResponse.of("테스트 title", "테스트 link")); - LLMAnswerResponse expectedResponse = LLMAnswerResponse.of(request.questionType(), request.questionCategory(), - Answer.of(question, "새로운 답변입니다."), references); - - mockWebServer.enqueue(new MockResponse() - .setHeader("Content-type", MediaType.APPLICATION_JSON_VALUE) - .setHeader("Accept", MediaType.APPLICATION_FORM_URLENCODED_VALUE) - .setResponseCode(200) - .setBody(new Gson().toJson(expectedResponse))); - - return answerApiClient.askQuestion(request).block(); - } - @DisplayName("질문을 조회하는데 성공한 경우") @Test void 질문_조회_성공() { @@ -174,6 +122,39 @@ private LLMAnswerResponse mockAskQuestion(LLMAskQuestionRequest request) { verify(answerManager, times(1)).processNewQuestion(eq(type), eq(category), eq(content), eq(contentToken)); } + @DisplayName("질문 조회 시 존재하지 않는 질문 ID로 인한 예외 처리") + @Test + void 질문_ID로_조회_시_존재하지_않는_질문_ID() { + // given + Long invalidQuestionId = 999L; + when(questionRepository.findById(invalidQuestionId)).thenReturn(Optional.empty()); + + // when & then + assertThrows(EntityNotFoundException.class, () -> { + questionProcessingService.getQuestion(invalidQuestionId); + }); + } + + @DisplayName("질문 검색 시 서버 내부 오류 발생하여 빈 배열 반환") + @Test + void 질문_검색_서버_내부_오류_빈배열_반환() { + // given + String contentToken = "서버 오류 테스트"; + QuestionType type = QuestionType.SUSI; + QuestionCategory category = QuestionCategory.ADMISSION_GUIDELINE; + List questionCores = List.of(); + + when(questionRepository.searchQuestionsByContentTokenAndTypeAndCategory(eq(contentToken), eq(type), + eq(category))) + .thenReturn(Optional.of(questionCores)); + + // when + questionProcessingService.question(type, category, "서버 오류 테스트"); + + // then + verify(answerManager, times(1)).processNewQuestion(eq(type), eq(category), eq("서버 오류 테스트"), eq(contentToken)); + } + @DisplayName("MOCK LLM 서버에 질문을 요청합니다.") @Test void MOCK_LLM_질문_요청() { @@ -198,4 +179,53 @@ private LLMAnswerResponse createExpectedLLMAnswerResponse() { Answer.of(question, "새로운 답변입니다."), List.of(AnswerReferenceResponse.of("테스트 title", "테스트 link"))); } + + private void setupMockEntities() { + question = mock(Question.class); + answer = mock(Answer.class); + references = List.of(AnswerReference.of("테스트 title", "테스트 link", answer)); + + when(question.getId()).thenReturn(1L); + when(answer.getId()).thenReturn(1L); + when(answer.getReferences()).thenReturn(references); + + when(answerManager.getAnswerByQuestionId(1L)).thenReturn(answer); + when(answerRepository.findByQuestionId(anyLong())).thenReturn(Optional.of(answer)); + + when(questionRepository.searchQuestionsByContentTokenAndTypeAndCategory(anyString(), any(QuestionType.class), + any(QuestionCategory.class))) + .thenReturn(Optional.of(List.of(QuestionCore.of(1L, "테스트 질문입니다.")))); + when(questionRepository.findById(1L)).thenReturn(Optional.of(question)); + } + + private void setupMockServer() { + this.mockWebServer = new MockWebServer(); + answerApiClient = new AnswerApiClient(WebClient.builder() + .baseUrl(this.mockWebServer.url("/").toString()) + .clientConnector(new ReactorClientHttpConnector()) + .build()); + } + + private void setupAnswerManagerMock() { + when(answerManager.getAnswerByQuestionId(anyLong())).thenReturn(answer); + } + + private LLMAnswerResponse mockAskQuestion(LLMAskQuestionRequest request) { + MultiValueMap formData = new LinkedMultiValueMap<>(); + formData.add("questionType", request.questionType()); + formData.add("questionCategory", request.questionCategory()); + formData.add("question", request.question()); + + List references = List.of(AnswerReferenceResponse.of("테스트 title", "테스트 link")); + LLMAnswerResponse expectedResponse = LLMAnswerResponse.of(request.questionType(), request.questionCategory(), + Answer.of(question, "새로운 답변입니다."), references); + + mockWebServer.enqueue(new MockResponse() + .setHeader("Content-type", MediaType.APPLICATION_JSON_VALUE) + .setHeader("Accept", MediaType.APPLICATION_FORM_URLENCODED_VALUE) + .setResponseCode(200) + .setBody(new Gson().toJson(expectedResponse))); + + return answerApiClient.askQuestion(request).block(); + } } \ No newline at end of file diff --git a/src/test/java/mju/iphak/maru_egg/question/application/QuestionServiceTest.java b/src/test/java/mju/iphak/maru_egg/question/application/QuestionServiceTest.java index d523093..eb60160 100644 --- a/src/test/java/mju/iphak/maru_egg/question/application/QuestionServiceTest.java +++ b/src/test/java/mju/iphak/maru_egg/question/application/QuestionServiceTest.java @@ -89,41 +89,6 @@ void setUp() { configureAnswerApiClient(); } - private void configureAnswerApiClient() { - doAnswer(invocation -> { - LLMAskQuestionRequest request = invocation.getArgument(0); - return Mono.just(mockAskQuestion(request)); - }).when(answerApiClient).askQuestion(any(LLMAskQuestionRequest.class)); - } - - private LLMAnswerResponse mockAskQuestion(LLMAskQuestionRequest request) { - startServer(new ReactorClientHttpConnector()); - MultiValueMap formData = new LinkedMultiValueMap<>(); - formData.add("questionType", request.questionType()); - formData.add("questionCategory", request.questionCategory()); - formData.add("question", request.question()); - - Question testQuestion = Question.of("새로운 질문입니다.", "새로운 질문", QuestionType.SUSI, - QuestionCategory.ADMISSION_GUIDELINE); - List references = List.of(AnswerReferenceResponse.of("테스트 title", "테스트 link")); - LLMAnswerResponse expectedResponse = LLMAnswerResponse.of(QuestionType.SUSI.getType(), - QuestionCategory.ADMISSION_GUIDELINE.getCategory(), Answer.of(testQuestion, "새로운 답변입니다."), references); - - mockWebServer.enqueue(new MockResponse() - .setHeader("Content-type", MediaType.APPLICATION_JSON_VALUE) - .setResponseCode(200) - .setBody(new Gson().toJson(expectedResponse))); - - return answerApiClient.askQuestion(request).block(); - } - - private void startServer(ClientHttpConnector connector) { - this.mockWebServer = new MockWebServer(); - answerApiClient = new AnswerApiClient(WebClient.builder() - .baseUrl(this.mockWebServer.url("/").toString()) - .clientConnector(connector).build()); - } - @AfterEach void tearDown() throws IOException { if (mockWebServer != null) { @@ -258,4 +223,40 @@ void tearDown() throws IOException { assertThat("id: 1인 질문을 찾을 수 없습니다.").isEqualTo(exception.getMessage()); } + + private void configureAnswerApiClient() { + doAnswer(invocation -> { + LLMAskQuestionRequest request = invocation.getArgument(0); + return Mono.just(mockAskQuestion(request)); + }).when(answerApiClient).askQuestion(any(LLMAskQuestionRequest.class)); + } + + private LLMAnswerResponse mockAskQuestion(LLMAskQuestionRequest request) { + startServer(new ReactorClientHttpConnector()); + MultiValueMap formData = new LinkedMultiValueMap<>(); + formData.add("questionType", request.questionType()); + formData.add("questionCategory", request.questionCategory()); + formData.add("question", request.question()); + + Question testQuestion = Question.of("새로운 질문입니다.", "새로운 질문", QuestionType.SUSI, + QuestionCategory.ADMISSION_GUIDELINE); + List references = List.of(AnswerReferenceResponse.of("테스트 title", "테스트 link")); + LLMAnswerResponse expectedResponse = LLMAnswerResponse.of(QuestionType.SUSI.getType(), + QuestionCategory.ADMISSION_GUIDELINE.getCategory(), Answer.of(testQuestion, "새로운 답변입니다."), references); + + mockWebServer.enqueue(new MockResponse() + .setHeader("Content-type", MediaType.APPLICATION_JSON_VALUE) + .setResponseCode(200) + .setBody(new Gson().toJson(expectedResponse))); + + return answerApiClient.askQuestion(request).block(); + } + + private void startServer(ClientHttpConnector connector) { + this.mockWebServer = new MockWebServer(); + answerApiClient = new AnswerApiClient(WebClient.builder() + .baseUrl(this.mockWebServer.url("/").toString()) + .clientConnector(connector).build()); + } + } \ No newline at end of file diff --git a/src/test/java/mju/iphak/maru_egg/question/application/QuestionTypeStatusServiceTest.java b/src/test/java/mju/iphak/maru_egg/question/application/QuestionTypeStatusServiceTest.java index 6756ec5..1baa3d7 100644 --- a/src/test/java/mju/iphak/maru_egg/question/application/QuestionTypeStatusServiceTest.java +++ b/src/test/java/mju/iphak/maru_egg/question/application/QuestionTypeStatusServiceTest.java @@ -9,10 +9,12 @@ import java.util.List; import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.mock.mockito.MockBean; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import jakarta.persistence.EntityNotFoundException; import mju.iphak.maru_egg.common.MockTest; @@ -23,12 +25,17 @@ class QuestionTypeStatusServiceTest extends MockTest { - @MockBean + @Mock private QuestionTypeStatusRepository questionTypeStatusRepository; - @Autowired + @InjectMocks private QuestionTypeStatusService questionTypeStatusService; + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + } + @DisplayName("질문 타입 상태 초기화 성공") @Test void initializeQuestionTypeStatus_Success() { From 9975acd443b9963d0e6e5f697f3b3be16d10c7dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=82=98=EA=B2=BD=ED=98=B8?= Date: Tue, 3 Sep 2024 00:49:13 +0900 Subject: [PATCH 2/2] =?UTF-8?q?test:=20integration=20test=20mocking=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20init=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../answer/api/AdminAnswerControllerTest.java | 59 ++++++++++++------- .../maru_egg/auth/api/AuthControllerTest.java | 4 +- .../api/AdminQuestionControllerTest.java | 56 ++++++++++-------- ...AdminQuestionTypeStatusControllerTest.java | 7 +-- .../question/api/QuestionControllerTest.java | 4 +- 5 files changed, 76 insertions(+), 54 deletions(-) diff --git a/src/test/java/mju/iphak/maru_egg/answer/api/AdminAnswerControllerTest.java b/src/test/java/mju/iphak/maru_egg/answer/api/AdminAnswerControllerTest.java index 1976275..e3d593f 100644 --- a/src/test/java/mju/iphak/maru_egg/answer/api/AdminAnswerControllerTest.java +++ b/src/test/java/mju/iphak/maru_egg/answer/api/AdminAnswerControllerTest.java @@ -1,40 +1,58 @@ package mju.iphak.maru_egg.answer.api; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import java.util.List; + +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.MockitoAnnotations; -import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.ResultMatcher; -import jakarta.persistence.EntityNotFoundException; import mju.iphak.maru_egg.answer.application.AnswerManager; +import mju.iphak.maru_egg.answer.domain.Answer; import mju.iphak.maru_egg.answer.dto.request.UpdateAnswerContentRequest; +import mju.iphak.maru_egg.answer.repository.AnswerRepository; import mju.iphak.maru_egg.common.IntegrationTest; +import mju.iphak.maru_egg.question.domain.Question; +import mju.iphak.maru_egg.question.domain.QuestionCategory; +import mju.iphak.maru_egg.question.domain.QuestionType; +import mju.iphak.maru_egg.question.repository.QuestionRepository; @WithMockUser(roles = "ADMIN") class AdminAnswerControllerTest extends IntegrationTest { - @MockBean + @Autowired private AnswerManager answerManager; + @Autowired + private QuestionRepository questionRepository; + + @Autowired + private AnswerRepository answerRepository; + @BeforeEach void setUp() { - MockitoAnnotations.openMocks(this); + initializeTestData(); + } + + @AfterEach + void tearDown() { + answerRepository.deleteAllInBatch(); + questionRepository.deleteAllInBatch(); } @Test void 답변_수정_API_정상적인_요청() throws Exception { // given - UpdateAnswerContentRequest request = new UpdateAnswerContentRequest(1L, "새로운 답변 내용"); + Long questionId = getFirstQuestionId(); + UpdateAnswerContentRequest request = new UpdateAnswerContentRequest(questionId, "새로운 답변 내용"); // when & then performRequestAndExpectStatus(request, status().isOk()); @@ -53,23 +71,11 @@ void setUp() { void 답변_수정_API_존재하지_않는_답변_ID() throws Exception { // given UpdateAnswerContentRequest request = new UpdateAnswerContentRequest(999L, "새로운 답변 내용"); - doThrow(new EntityNotFoundException("답변을 찾을 수 없습니다.")).when(answerManager) - .updateAnswerContent(anyLong(), anyString()); // when & then performRequestAndExpectStatus(request, status().isNotFound()); } - @Test - void 답변_수정_API_서버_내부_오류() throws Exception { - // given - UpdateAnswerContentRequest request = new UpdateAnswerContentRequest(1L, "새로운 답변 내용"); - doThrow(new RuntimeException("내부 서버 오류")).when(answerManager).updateAnswerContent(anyLong(), anyString()); - - // when & then - performRequestAndExpectStatus(request, status().isInternalServerError()); - } - private void performRequestAndExpectStatus(Object content, ResultMatcher expectedStatus) throws Exception { ResultActions resultActions = mvc.perform(put("/api/admin/answers") .contentType(MediaType.APPLICATION_JSON) @@ -85,4 +91,17 @@ private void performRequestAndExpectStatus(String content, ResultMatcher expecte resultActions.andExpect(expectedStatus).andDo(print()); } + + private void initializeTestData() { + Question question = Question.of("질문", "질문", QuestionType.SUSI, QuestionCategory.ADMISSION_GUIDELINE); + Answer answer = Answer.of(question, "답변"); + + questionRepository.saveAndFlush(question); + answerRepository.saveAndFlush(answer); + } + + private Long getFirstQuestionId() { + List questions = questionRepository.findAll(); + return questions.get(0).getId(); + } } \ No newline at end of file diff --git a/src/test/java/mju/iphak/maru_egg/auth/api/AuthControllerTest.java b/src/test/java/mju/iphak/maru_egg/auth/api/AuthControllerTest.java index 892ba41..2fd2540 100644 --- a/src/test/java/mju/iphak/maru_egg/auth/api/AuthControllerTest.java +++ b/src/test/java/mju/iphak/maru_egg/auth/api/AuthControllerTest.java @@ -8,7 +8,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.http.MediaType; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.test.web.servlet.MockMvc; @@ -29,7 +29,7 @@ class AuthControllerTest extends IntegrationTest { @Autowired private ObjectMapper objectMapper; - @MockBean + @SpyBean private AuthService authService; @Autowired diff --git a/src/test/java/mju/iphak/maru_egg/question/api/AdminQuestionControllerTest.java b/src/test/java/mju/iphak/maru_egg/question/api/AdminQuestionControllerTest.java index 0201ab4..41647f1 100644 --- a/src/test/java/mju/iphak/maru_egg/question/api/AdminQuestionControllerTest.java +++ b/src/test/java/mju/iphak/maru_egg/question/api/AdminQuestionControllerTest.java @@ -1,43 +1,52 @@ package mju.iphak.maru_egg.question.api; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import java.util.List; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.MockitoAnnotations; -import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.ResultActions; -import jakarta.persistence.EntityNotFoundException; +import mju.iphak.maru_egg.answer.domain.Answer; import mju.iphak.maru_egg.answer.dto.request.CreateAnswerRequest; +import mju.iphak.maru_egg.answer.repository.AnswerRepository; import mju.iphak.maru_egg.common.IntegrationTest; import mju.iphak.maru_egg.question.application.QuestionService; +import mju.iphak.maru_egg.question.domain.Question; import mju.iphak.maru_egg.question.domain.QuestionCategory; import mju.iphak.maru_egg.question.domain.QuestionType; import mju.iphak.maru_egg.question.dto.request.CheckQuestionRequest; import mju.iphak.maru_egg.question.dto.request.CreateQuestionRequest; +import mju.iphak.maru_egg.question.repository.QuestionRepository; @WithMockUser(roles = "ADMIN") class AdminQuestionControllerTest extends IntegrationTest { - @MockBean + @Autowired private QuestionService questionService; + @Autowired + private QuestionRepository questionRepository; + + @Autowired + private AnswerRepository answerRepository; + @BeforeEach void setUp() { - MockitoAnnotations.openMocks(this); + initializeTestData(); } @Test void 질문_체크_API_정상적인_요청() throws Exception { // given - CheckQuestionRequest request = new CheckQuestionRequest(1L); + Long questionId = getFirstQuestionId(); + CheckQuestionRequest request = new CheckQuestionRequest(questionId); // when ResultActions resultActions = performCheckQuestionRequest(request); @@ -62,8 +71,6 @@ void setUp() { void 질문_체크_API_존재하지_않는_질문_ID() throws Exception { // given CheckQuestionRequest request = new CheckQuestionRequest(999L); - doThrow(new EntityNotFoundException("질문을 찾을 수 없습니다.")).when(questionService) - .checkQuestion(anyLong()); // when ResultActions resultActions = performCheckQuestionRequest(request); @@ -72,20 +79,6 @@ void setUp() { resultActions.andExpect(status().isNotFound()); } - @Test - void 질문_체크_API_서버_내부_오류() throws Exception { - // given - CheckQuestionRequest request = new CheckQuestionRequest(1L); - doThrow(new RuntimeException("내부 서버 오류")).when(questionService) - .checkQuestion(anyLong()); - - // when - ResultActions resultActions = performCheckQuestionRequest(request); - - // then - resultActions.andExpect(status().isInternalServerError()); - } - @Test void 질문_생성_API() throws Exception { // given @@ -101,7 +94,7 @@ void setUp() { @Test void 질문_삭제_API() throws Exception { // given - Long id = 1L; + Long id = getFirstQuestionId(); // when ResultActions resultActions = performDeleteQuestionRequest(id); @@ -110,6 +103,11 @@ void setUp() { resultActions.andExpect(status().isOk()); } + private Long getFirstQuestionId() { + List questions = questionRepository.findAll(); + return questions.get(0).getId(); + } + private ResultActions performCheckQuestionRequest(CheckQuestionRequest request) throws Exception { return mvc.perform(put("/api/admin/questions/check") .contentType(MediaType.APPLICATION_JSON) @@ -142,4 +140,12 @@ private CreateQuestionRequest createSampleCreateQuestionRequest() { QuestionCategory.ADMISSION_GUIDELINE, new CreateAnswerRequest("example answer content", 2024)); } + + private void initializeTestData() { + Question question = Question.of("질문", "질문", QuestionType.SUSI, QuestionCategory.ADMISSION_GUIDELINE); + Answer answer = Answer.of(question, "답변"); + + questionRepository.saveAndFlush(question); + answerRepository.saveAndFlush(answer); + } } \ No newline at end of file diff --git a/src/test/java/mju/iphak/maru_egg/question/api/AdminQuestionTypeStatusControllerTest.java b/src/test/java/mju/iphak/maru_egg/question/api/AdminQuestionTypeStatusControllerTest.java index 1765328..2cfc71e 100644 --- a/src/test/java/mju/iphak/maru_egg/question/api/AdminQuestionTypeStatusControllerTest.java +++ b/src/test/java/mju/iphak/maru_egg/question/api/AdminQuestionTypeStatusControllerTest.java @@ -7,7 +7,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.security.test.context.support.WithMockUser; @@ -26,7 +25,6 @@ class AdminQuestionTypeStatusControllerTest extends IntegrationTest { @BeforeEach void setUp() { - MockitoAnnotations.openMocks(this); questionTypeStatusService.initializeQuestionTypeStatus(); questionTypeStatusService.deleteQuestionTypeStatus(QuestionType.JEONGSI); } @@ -34,7 +32,7 @@ void setUp() { @DisplayName("200 질문 상태 초기화") @Test public void 질문_상태_초기화_API_정상적인_요청() throws Exception { - // given // when + // given & when ResultActions resultActions = performInitializeQuestionTypeStatus(); // then @@ -80,5 +78,4 @@ private ResultActions performUpdateQuestionTypeStatus(UpdateQuestionTypeStatusRe .content(objectMapper.writeValueAsString(request))) .andDo(print()); } - -} \ No newline at end of file +} diff --git a/src/test/java/mju/iphak/maru_egg/question/api/QuestionControllerTest.java b/src/test/java/mju/iphak/maru_egg/question/api/QuestionControllerTest.java index fbe7d3c..94f4840 100644 --- a/src/test/java/mju/iphak/maru_egg/question/api/QuestionControllerTest.java +++ b/src/test/java/mju/iphak/maru_egg/question/api/QuestionControllerTest.java @@ -64,7 +64,7 @@ class QuestionControllerTest extends IntegrationTest { @BeforeEach void setUp() { setupDatabase(); - setupEntities(); + initializeTestData(); } private void setupDatabase() { @@ -76,7 +76,7 @@ private void setupDatabase() { jdbcTemplate.execute("ALTER TABLE questions ADD FULLTEXT INDEX idx_ft_question_content(content)"); } - private void setupEntities() { + private void initializeTestData() { content = "수시 원서 일정 알려주세요."; question = questionRepository.save( Question.of(content, "수시 일정", QuestionType.SUSI, QuestionCategory.ADMISSION_GUIDELINE));