spring mock test

이번엔 spring mock test에 대해서 알아 볼 것이다.
mock 으로 테스트를 잘 하지 않아서 익숙하지 않다.
그래서 이제부터는 mock test를 사용 하도록 노력 할라고 하는 중이다.
일단 spring boot로 할 것이다.
그래서 아래와 같이 메이븐을 추가하자.

<dependency>
    <groupId>com.jayway.jsonpath</groupId>
    <artifactId>json-path</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>

일단 기본적으로 테스트에 필요한 라이브러리다.
첫번째는 json-path 여기에 자세히 나와있다.
두번째는 spring test를 위한 mock 라이브러리다.
이번에도 스칼라도 했다. 흠하

일단 테스트 클래스에 아래와 같이 어노테이션을 추가 한다.

@RunWith(classOf[SpringJUnit4ClassRunner])
@SpringApplicationConfiguration(Array(classOf[SpringBootConfig]))
@WebAppConfiguration
@FixMethodOrder(MethodSorters.JVM)

첫번째는 Spring에서 제공하는 Runner다
두번째는 Spring Boot를 사용해서 저 어노테이션을 쓴거다. 빈 들을 관리해준다.
Boot를 쓰지 않았을때는 @ContextConfiguration 어노테이션을 썼다. 물론 SpringApplicationConfiguration 안에 ContextConfiguration 포함되어 있다.
세번째는 WebApplicationContext를 생성해주는 아이다.
네번째는 필수 사항이 아니다. 테스트 순서를 정하는 거다.
테스트를 위해 아래와 같이 셋팅 해주자.

var objectMapper: ObjectMapper = _

var mockMvc: MockMvc = _

@Autowired
var wac: WebApplicationContext = _

@Before
def before: Unit = {
  objectMapper = new ObjectMapper
  mockMvc = MockMvcBuilders.webAppContextSetup(wac).build
}

objectMapper는 다들 아시다 시피 json으로 값을 넘길때 사용 할거다.
mockMvc를 선언한다.
그리고 WebApplicationContext 는 mockMvc를 생성하기 위해서 필요하다.
before 메소드에 objectMapper와 mockMvc 생성해준다.

일단 코드 부터 보자

@Test
@Test
def mockTest: Unit = {
  mockMvc.perform(get("/accounts") header ("Accept","application/json")  contentType(MediaType.APPLICATION_JSON))
    .andDo(print())
    .andExpect(status isOk)
    .andExpect(handler handlerType (classOf[AccountController]))
    .andExpect(handler methodName ("accounts"))
    .andExpect(content contentType(MediaType.APPLICATION_JSON_UTF8))
    .andExpect(jsonPath("$.content[0].name", is("wonwoo")))
    .andExpect(jsonPath("$.content[1].name", is("kevin")))
}

첫번째줄은 Http method와 url, 헤더 정보를 셋팅 할 수 있다. contentType와 accpet를 셋팅 했다. contentType처럼 메소드를 사용 할 수 있고
커스텀 header 도 설정 할 수 있다.
이 외 에도 accept, cookie, locale, sessionAttr, session, principal 등 여러가지 메소드가 존재 한다.
print() 는 request response 정보를 콘솔창에 출력해준다.
status.isOk 는 http code가 200일 경우를 체크 하는거다.
이 외 에도 isCreated, isNoContent, isBadRequest, isUnauthorized, isNotFound 등 이 있다. 자주 쓰는 것만 넣어뒀다.
웬만한 http code가 다 있는 듯하다.
handler.handlerType은 요청 컨트롤러이다.
handler methodName은 요청 메소드이다.
content.contentType은 response의 미디어 타입이다.
일단 여기 까지 성공 되었다면 다음은 데이터를 확인할 차례이다.
json-path 라이브러리를 추가한 이유이다.
문법은 저기 링크에 자세히 나와있다.
content 키를 갖고 있는 배열의 첫번째 name이 wonwoo와 같은지 비교하는거다.
만약 틀린다면 에러를 내뱉는다.

코드를 좀더 보자.

@Test
def mockTest1: Unit = {
  mockMvc.perform(get("/account/{id}", 2.asInstanceOf[Object]) contentType (MediaType.APPLICATION_JSON))
    .andDo(print())
    .andExpect(status isOk)
    .andExpect(handler handlerType (classOf[AccountController]))
    .andExpect(handler methodName ("account"))
    .andExpect(jsonPath("$.name", is("kevin")))
}

urlTemplate 처럼 만들 수도 있다.
나머지는 같지만 단일 데이터이기 때문에 $.name 이렇게 했다.

mockMvc.perform(get("/account/search") param("name", "wonwoo")

이렇게 파라미터로 보낼 수도 있다.

@Test
def mockTest4: Unit = {

  val account = new Account()
  account.setId(3L);
  account.setName("mockTest")
  account.setPassword("pwMockTest")

  mockMvc.perform(post("/account")
    contentType (MediaType.APPLICATION_JSON)
    content (objectMapper.writeValueAsString(account)))
    .andDo(print())
    .andExpect(status isCreated)
    .andExpect(jsonPath("$.name", is("mockTest")))
    .andExpect(jsonPath("$.password", is("pwMockTest")))
}

이번엔 requestbody로 보내는 데이터를 만들었다.
objectMapper 를 이용해서 엔티티빈을 json String으로 만들었다.
http code는 201로 생성 했다고 코드를 받았다.

이렇게 테스트 케이스를 만들어서 사용할 예정이다.
예전엔 그냥 크롬 확장프로그램에서 Advanced REST client를 썼는데 이젠 테스트 케이스를 만들어서 사용 해야 겠다.