SpringBoot - MockMvc

이세영·2022년 11월 16일
0

mockMvc란?

Mock의 사전적 의미는 '테스트를 위해 만든 모형'을 의미한다.

mocking : 테스트를 위해 실제 객체와 비슷한 모의 객체를 만드는 것

mock-up : 모킹한 객체를 메모리에서 얻어 내는 과정

mockMvc란 실제 객체와 비슷하지만 테스트에 필요한 기능만 가지는 가짜 객체를 만들어서 애플리케이션 서버에 배포하지 않고도 스프링 MVC 동작을 재현할 수 있는 클래스를 의미한다.

mocMvc 를 이용해서 Controller를 테스트 할 수 있다.

웹 환경에서 컨트롤러를 테스트 하려면 반드시 서블릿 컨테이너가 구동되고 DIspatcherServlet객체가 메모리에 올라가야 한다. 서블릿 컨테이너를 모킹하면 실제 서블릿 컨테이너가 아닌 테스트용 모형 컨테이너를 사용하여 간단하게 컨트롤러를 테스트 할 수 있다.

서블릿 컨테이너를 모킹할 떄 두 가지 어노테이션을 사용할 수 있다.

- @webMvcTest : @Controller, @RestController가 설정된 클래스를 찾아 메모리 생성
(@service, @repository 불가능)
- @AutoConfigureMockMvc : @Controller, @RestController, @service, @repository 등이 설정된 클래스들 모두 메모리 생성

mockMvc의 메소드

메소드명 메소드 특징
perform() 요청을 전송하는 역할. ResultActions 객체를 받으며, 해당 객체는 리턴 값을 검증하고 확일할 수 있는 andExpect()메소드를 제공한다.
get("/경로") Http 메소드(get, post, put, delete) 결정. 인자로 경로를 보내준다
param("key", "value") "key" = "value" 의 파라미터를 전달 할 수 있다. "key"="value" 파라미터를 여러 개 전달 할 경우 params()를 사용한다.
perform() 응답을 검증하는 역할.
응답메소드 역할
status() 상태를 검증한다.
- isOk() :200
- isNotFound() :404
- isMethodNotAllowed():405
- isInternalServalError():500
- is(int stautus) : status 상태코드
   예) 200, 404, 405 등
view() 컨트롤러에서 리턴하는 뷰 이름을 검증한다.
예) andExpect(view().name("hello"))
redirect() 컨트롤러에서 리다이렉트 응답을 검증한다.
예) andExpect(redirectedUrl("/hello"))
model() 컨트롤러에서 저장한 모델들의 정보를 검증한다.
attributeExists(String name) : name에 해당하는 데이터가 Model에 포함되어 있는지 검증한다.
attribute(String name, Object name) : name에 해당하는 데이터가 value객체인지 검증한다.
content() 응답에 대한 정보를 검증한다.
perform() 요청을 전송하는 역할. ResultActions 객체를 받으며, 해당 객체는 리턴 값을 검증하고 확일할 수 있는 andExpect()메소드를 제공한다.

MockMvc 사용해보기 - mockMvc 를 이용해서 Controller 테스트 하기

pom.xml에 Junit4를 사용하기 위해 spring-boot-start-test를 추가해준다.

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

임포트가 되지 않을 경우 Junit maven을 추가해주어도 된다.

https://mvnrepository.com/ 에서 필요한 dependency를 가지고 올 수 있다.

Controller 테스트에 필요한 객체 생성

링크텍스트

mockMvc 를 통한 Controller 테스트를 하기 전 필요한 객체를 생성한다.

Domain, Service, ServiceImpl, Controller

(1) Domain

@Data
public class Person {
   private String name;
   private int age;
}

(2) Service

public interface PersonService {

	String hello(String name);
	Person getPerson();
	List<Person> getPersonList();
}

(3) ServiceImpl

@Service
public class PersonServiceImpl implements PersonService {

	@Override
	public String hello(String name) {
		return "Hello : " + name;
	}

	@Override
	public Person getPerson() {
      Person person = new Person();
      
      person.setName("selffy");
      person.setAge(27);
      
      return person;

	}

	@Override
	public List<Person> getPersonList() {
      Person person1 = new Person();
      person1.setName("selffy");
      person1.setAge(27);
      
      Person person2 = new Person();
      person2.setName("Nana");
      person2.setAge(27);
      
      List<Person> personList = new ArrayList<Person>();
      
      personList.add(person1);
      personList.add(person2);
      
      return personList;

	}

}

서비스 객체와 도메인 객체를 생성한 후 해당 서비스를 불러올 수 있는 Controller를 생성한다.

2. Controller. ControllerTest 클래스 생성

테스트 클래스를 생성하기 앞서 서블릿 컨테이너를 어떤 어노테이션이 모킹하냐에 따라 조금 다르다.

@webMvcTest 어노테이션을 활용할 경우, @service 객체를 메모리에 생성할 수 없기 때문에 위에서 생성한 서비스 객체를 사용하지 않고 controller에 필요한 코드를 작성한다.

@RestController
public class PersonController {
	
	@GetMapping("/hello")
	public String hello(String name) {
        return "Hello : " + name;
	}
내용을 입력하세요.
1) @webMvcTest

해당 테스트 실행 결과는 아래와 같다.


@RunWith(SpringRunner.class)
@WebMvcTest
@SpringBootTest
public class BoardControllerTest {
	
	@Autowired
	private MockMvc mockMvc;
	
	@Test
	public void testHello() throws Exception {
		mockMvc.perform(get("/hello").param("name", "셀피"))
		.andExpect(status().isOk())
		.andExpect(content().string("Hello : 셀피"))
		.andDo(print());
	}
내용을 입력하세요.

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /hello
       Parameters = {name=[셀피]}
          Headers = []
             Body = null
    Session Attrs = {}
Handler:
             Type = kr.kwangan2.test.controller.BoardController
           Method = kr.kwangan2.test.controller.BoardController#hello(String)
Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null
FlashMap:
       Attributes = null
MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"14"]
     Content type = text/plain;charset=UTF-8
             Body = Hello : 셀피
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

2) @AutoConfigureMockMvc

@RestController
public class PersonController  {

	@Autowired
	private PersonService service;

	@GetMapping("/hello")
	public String hello(String name) {
		return service.hello(name);
	}

Controller를 테스트 하기 위해 src/test/java 패키지에 테스트 클래스를 생성한다.
@service가 주입된 객체의 메모리 또한 생성하기 위해 @AutoConfigureMockMvc 를 임포트한다.

mockMvc 테스트 (ControllerTEST)

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
@AutoConfigureMockMvc
public class PersonControllerTest4{

	@Autowired
	private MockMvc mockMvc;
	
	@MockBean
	private PersonService service;
	
	@Test
	public void testHello() throws Exception{
		when(service.hello("selffy")).thenReturn("Hello : sellfy");
		
		mockMvc.perform(get("/hello").param("name", "selffy"))
		.andExpect(status().isOk())
		.andExpect(content().string("Hello : selffy"))
		.andDo(print());
	}

테스트 실행 결과는 아래와 같다.

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /hello
       Parameters = {name=[selffy]}
          Headers = []
             Body = null
    Session Attrs = {}

Handler:
             Type = kr.kwangan2.test.controller.BoardController
           Method = kr.kwangan2.test.controller.BoardController#hello(String)

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = [Content-Type:"text/plain;charset=UTF-8", Content-Length:"14"]
     Content type = text/plain;charset=UTF-8
             Body = Hello : selffy
    Forwarded URL = null
   Redirected URL = null
          Cookies = []
profile
꿈나무개발자

0개의 댓글