Spring/Test

태태개발일지 - Controller계층 Test

태태코 2024. 6. 9. 19:54
반응형

단위별 테스트 작성

 

저번 글과 이어서 이번에는 Controller 계층에 테스트를 진행시켜보도록 하겠다.

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

이 의존성을 통해서 결과값을 확인할 수 있음.

import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.when;
@WebMvcTest(controllers = UserApiController.class)
@AutoConfigureMockMvc(addFilters = false)
@ExtendWith(MockitoExtension.class)
class UserApiControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private UserBusiness userBusiness;

    private final ObjectMapper objectMapper = new ObjectMapper();

    @BeforeEach
    void setUp() {
        mockMvc = MockMvcBuilders.standaloneSetup(new UserApiController(userBusiness)).build();
    }

    @Test
    void getUserByEmail() throws Exception {
        // Mock the business method using when().thenReturn()
        UserResponse userResponse = new UserResponse(1L,"Taehwan", "Taehwan@gmail.com", LocalDateTime.now(),LocalDateTime.now());
        when(userBusiness.getUserByEmail("Taehwan@gmail.com")).thenReturn(userResponse);

        mockMvc.perform(get("/api_user/Taehwan@gmail.com")
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isAccepted())
                .andExpect(jsonPath("$.userName").value("Taehwan"))
                .andExpect(jsonPath("$.userEmail").value("Taehwan@gmail.com"));
    }

    @Test
    void getUserByEmailTest() throws Exception{
        LocalDateTime now = LocalDateTime.now();
        String nowString = now.toString(); // ISO-8601 형식 문자열

        UserResponse userResponse = new UserResponse(1L,"Taehwan", "Taehwan@gmail.com", now,now);
        UserResponse userResponse2 = new UserResponse(2L,"Taehwan", "Taehwan@gmail.com", now,now);
        List<UserResponse> userResponseList = List.of(userResponse2,userResponse);
        when(userBusiness.findByUserNameAndCreatedAt("Taehwan",now)).thenReturn(userResponseList);

        mockMvc.perform(get("/api_user/Taehwan/" + nowString)
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isAccepted())
                .andDo(print())
                .andExpect(jsonPath("$[0].userName").value("Taehwan"))
                .andExpect(jsonPath("$[0].userEmail").value("Taehwan@gmail.com"))
                .andExpect(jsonPath("$[1].userName").value("Taehwan"))
                .andExpect(jsonPath("$[1].userEmail").value("Taehwan@gmail.com"));

    }

}

 

 

주요 어노테이션 및 클래스:

@WebMvcTest: Spring MVC 컨트롤러를 테스트하는 데 사용됩니다. UserApiController만 로드하여 테스트합니다.

@AutoConfigureMockMvc: MockMvc를 자동 구성합니다. addFilters = false는 보안 필터를 비활성화하여 인증 없이 테스트를 수행할 수 있게 합니다.

@ExtendWith(MockitoExtension.class): Mockito 확장을 사용하여 Mockito의 애노테이션을 활성화합니다.

@MockBean: Spring 애플리케이션 컨텍스트에 모킹된 빈을 추가합니다. UserBusiness를 모킹하여 테스트합니다.

 

클래스 필드:

 

@Autowired MockMvc: MockMvc 인스턴스를 자동 주입하여 사용합니다.

@MockBean UserBusiness:** UserBusiness를 모킹하여 테스트에서 사용할 수 있도록 합니다.

ObjectMapper: JSON 직렬화 및 역직렬화를 위해 사용됩니다.

 

주요 기능 요약:

MockMvc: HTTP 요청을 시뮬레이션하고 응답을 검증합니다.

mockMvc.perform(): HTTP 요청을 시뮬레이션합니다.

andExpect(): 응답 상태 코드와 JSON 응답 본문의 내용을 검증합니다.

andDo(print()): 요청 및 응답 내용을 콘솔에 출력합니다.

 

mockMvc.perform 와 http.MediaType을 통해서 

mockMvc.perform(get("/api_user/Taehwan/" + nowString)
                .contentType(MediaType.APPLICATION_JSON))
        .andExpect(status().isAccepted())


아래 이 구문을 실행 할 수 있는 것이다.

 

여기서 등장한 부분이 


BDD (Behavior Driven Development)

코드보다 인간의 언어와 유사하게 구성되어야 한다.

BDD는 TDD를 수행하려는 어떤한 행동과 기능을 개발자가 더 이해하기 쉽게하는 것이 목적이다.

모든 테스트 문장은 Given When Then으로 나눠서 작성할 수 있어야 한다.

 

순수 Mockito에서 BDD의 Given/When/Then을 사용하기 위해서 다음과 같이 when(obj) 메서드와 thenReturn() 메서드를 이용하고 verity() 구문을 이용해 검증한다. 그렇기에 given then이 더 어울린다.

 

예시를 보면 

given(Class.method()).willReturn()

이렇기 때문에 조금더 Given When Then과 비슷해진다.

 

반복문이있을때는

given(mockRepo.getOne(1L)).willReturn(new Object(1L));
given(mockRepo.getOne(2L)).willReturn(new Object(2L));
given(mockRepo.getOne(3L)).willReturn(new Object(3L));

 

given(mockRepo.getOne(anyLong()))
              .willAnswer(id -> new Object(id)));


willAnswer을 통해서 람다 형식을 통해서 해결할 수 있다.

반응형

'Spring > Test' 카테고리의 다른 글

태태개발일지 - Service 계층 Test  (0) 2024.06.09
태태개발일지 -TestCode 편  (0) 2024.06.09