Spring Framework MVC Controller Unit Test
SpringRunner 또는 SpringJUnit4ClassRunner 를 사용하지 않은 Controller 단위 테스트
jsonpath를 사용하지 않고 json 요청과 응답에 대한 테스트
- 사용한 라이브러리
- Mockito
- assertj
- junit4
- spring-test
package junseok.temp.controller;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import junseok.temp.service.TempService;
import junseok.temp.controller.TempController;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
import static org.assertj.core.api.Assertions.*;
public class TempControllerTest {
@Mock
private TempService tempService;
@InjectMocks
private TempController tempController;
private MockMvc mockMvc;
private final String BASE_URL = "/baseurl";
private final String APPLICATION_JSON_UTF8 = "application/json;charset=UTF-8";
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(tempController).build();
}
@Test
public void test_one() throws Exception {
final String TARGET_URL = "/url.do";
final String EXPECT_VIEW_NAME = "viewname";
String url = new StringBuffer(BASE_URL).append(TARGET_URL).toString();
this.mockMvc.perform(get(url))
.andDo(print())
.andExpect(status().isOk())
.andExpect(view().name(EXPECT_VIEW_NAME));
}
@Test
public void test_two() throws Exception {
final String REQ_JSON_BODY = "{ \"data\": { \"empNo\": \"00874\", \"yymm\": \"2018\"} }";
final String RES_JSON_BODY = "{\"errorCode\":\"0\",\"message\":\"\",\"progrmId\":\"\",\"docId\":\"\",\"total\":2,\"errorCalendar\":null,\"data\":[{\"yymm\":\"2018\"},{\"yymm\":\"2019\"}],\"aggregates\":null,\"errorMessage\":\"\"}";
ResultActions reqResult = this.mockMvc.perform(post(url)
.content(REQ_JSON_BODY)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andDo(print());
reqResult.andExpect(content().string(RES_JSON_BODY));
reqResult.andExpect(status().isOk());
reqResult.andExpect(content().contentType(APPLICATION_JSON_UTF8));
}
@Test
public void selectSalTax() throws Exception {
.
.
.
when(TempService.selectSalTax(request.getData())).thenReturn(salTax);
this.mockMvc.perform(post(TARGET_URL)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content(reqBodyJson))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON_UTF8))
.andExpect(content().string(resultBodyJson));
}
@Test
public void selectIncentiveTax() throws Exception {
.
.
.
MockHttpServletResponse response = this.mockMvc.perform(post("/url.json")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content(reqBodyString))
.andDo(print())
.andReturn().getResponse();
String contentType = response.getContentType();
int status = response.getStatus();
String bodyAsString = response.getContentAsString();
DataSourceResult dataSourceResult = new DataSourceResult();
dataSourceResult.setData(makeIncenTax);
String resBodyString = objectMapper.writeValueAsString(dataSourceResult);
assertThat(contentType).isEqualTo(APPLICATION_JSON_UTF8);
assertThat(status).isEqualTo(HttpStatus.OK.value());
assertThat(bodyAsString).isEqualTo(resBodyString);
}
}
중요한 부분만 제외하고 거의 대부분 생략
완성된 코드에서 이름만 조금씩 바꾸고 생략해서 실제 컴파일 오류는 확인하지 않음.
알아두어야 하는 키워드
@Mock@InjectMocks- json 문자열 작성 방법
objectMapper.writeValueAsStringMockMvcBuilders.standaloneSetupMockitoAnnotations.initMocks(this)
MockMvcBuilders.standaloneSetup
스프링 구성을로드하지 않고 컨트롤러 인스턴스를 수동으로 생성하는 것입니다.
대신 MVC JavaConfig 또는 MVC 네임 스페이스와 비슷한 기본 기본 구성이 자동으로 생성됩니다.
어느 정도 사용자 정의 할 수 있습니다.
objectMapper.writeValueAsString
Java 값을 문자열로 직렬화하는 데 사용할 수있는 메소드입니다.
StringWriter로 writeValue(Writer, Object)를 호출하고 String을 구성하는 것과 기능상 동일하지만보다 효율적입니다.
MockitoAnnotations.initMocks
Mockito 관련 annotation을 사용하기 위해 필요합니다.
@RunWith(MockitoJUnitRunner) 를 대신 사용할 수도 있습니다.