[Spring]Spring MVC JUnit 활용하기2(MockMvc를 활용한 Controller 단위테스트)

Spring MVC 프로젝트에서 JUnit과 MockMvc를 활용한 Controller 단위테스트하기

Imagem de capa

Spring MVC JUnit 활용하기 에서 JUnit을 활용한 서비스 단위테스트를 진행하였다. 이번에는 JUnit과 MockMvc를 활용하여 Contrller의 단위테스트를 진행해보도록 하자.


  1. MocMvc란?

브라우저에서의 요청과 응답을 의미하는 객체로서 Controller 테스트를 용이하게 해주는 라이브러리이며 기존의 MockHttpServletRequest, MockHttpServletREsponse를 활용한 단위테스트에서 발전되었다. MockMvc는 Spring3.2부터 사용 가능하며 Spring-test 라이브러리에 포함되어 있다.


  1. MockMvc를 활용한 Controller 테스트 방법

1) pom.xml에 spring-test 및 JUnit 라이브러리를 추가한다.(maven repo에서 최신버전으로 적용한다.)

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>	<!-- WebAppConfiguration을 사용하기 위함 -->
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
        </dependency>


2) Test 대상인 클래스를 생성한다.(서비스, 컨트롤러)

src/main/java/com/test/service/TestService.java

package com.test.service;

import org.springframework.stereotype.Service;

@Service
public class TestService {

    public boolean numberCompare(int number1, int number2) {
        if (number1 == number2) {
            return true;
        } else {
            return false;
        }
    }
}

src/main/java/com/test/controller/TestController.java

package com.test.controller;


import com.test.service.TestService;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

    @Setter(onMethod_ = {@Autowired})
    private TestService testService;

    @GetMapping(value = "/test")
    public boolean test(@RequestParam int number1, @RequestParam int number2) {
        return testService.numberCompare(number1, number2);
    }
}



3) test/java 밑에 JUnit 컨트롤러 테스트 클래스를 생성한다.(이 블로그에서는 test/java/com/test/ControllerTests.java 생성)

package com.test;


import com.test.controller.TestController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

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.status;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"file:src/main/webapp/WEB-INF/spring-config/applicationContext.xml", "file:src/main/webapp/WEB-INF/spring-config/dispatcher-servlet.xml"}) // xml 설정을 읽어 스프링 테스트 시작   초기화  스프링 설정 업로드
@WebAppConfiguration	// WebApplicationContext 생성할  있도록 하는 어노테이션
public class ControllerTests {

    private WebApplicationContext context; // MockMvc 객체 생성을 위한 context
    private MockMvc mockMvc;

    @Autowired
    TestController testController;	// 테스트를 진행할 controller

    @Before
    public void setUp() {
        this.mockMvc = MockMvcBuilders.standaloneSetup(testController).build();     // test 위한 MockMvc 객체 생성. testController 1개만 주입.
//        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();  // test 위한 MockMvc 객체 생성. 스프링이 로드한 WebApplicationContext 인스턴스로 작동.(standaloneSetup()   1)
    }

    @Test
    public void test() throws Exception {
        mockMvc.perform(get("/test")        // controller /test URI get방식으로 호출
                .param("number1", "1")  // 파라미터 number1 1 입력
                .param("number2", "1")) // 파라미터 number2 1입력
                .andDo(print())                        // 결과를 print. MockMvcBuilders alwaysDo(print()) 대체 가능
                .andExpect(status().isOk());           // 호출 결과값이 OK 나오면 정상처리
    }
}


4) 코드 간단 설명

4-1) @WebAppConfiguration


4-2) MockMvc


4-3) setup()


4-4) perform()

== post() 예제코드 ==

package com.tpcom_apr.service;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.tpcom_apr.controller.HomeController2;
import com.tpcom_apr.domain.OnmsgchkInputVO;
import lombok.extern.log4j.Log4j;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

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

@RunWith(SpringJUnit4ClassRunner.class) // SpringJunit4ClassRunner.class spring-test에서 제공하는 단위테스르를 위한 클래스 러너
@WebAppConfiguration    // WebApplicationContext 생성할  있도록 하는 어노테이션
@ContextConfiguration({"file:src/main/webapp/WEB-INF/spring-config/applicationContext.xml", "file:src/main/webapp/WEB-INF/spring-config/dispatcher-servlet.xml"})
public class MockMvcTests {
    @Autowired
    private WebApplicationContext context; // MockMvc 객체 생성을 위한 context
    private MockMvc mockMvc;    // controller request 수행해주는 mock 객체
    ObjectMapper mapper; // 객체를 json 형식으로 변경  사용

    @Autowired
    HomeController2 homeController2;

    @Before // @Test 이전에 실행
    public void setUp() {
        this.mockMvc = MockMvcBuilders.standaloneSetup(homeController2).build();
        mapper = new ObjectMapper();
    }
    @Test
    public void testOk() throws Exception {
        mockMvc.perform(post("/test")        // Controller /test URI Post방식으로 호출
                .contentType(MediaType.APPLICATION_JSON_VALUE)    // contentType json 형식
                .content(mapper.writeValueAsString(         // 객체를 json 변경. content에는 post body 들어감.
                        new TestInputVO(
                                "useService11",
                                "S40",
                                "xxxx",
                                "1111",
                                "2222")))
                .andExpect(status().isOk())                 // 상태값은 OK 나오면 정상처리
                .andDo(print());                            // 처리 내용을 출력
    }
}

4-5) ResultActions


4-6) jsonPath


5) JUnit 테스트를 실행한다.(Alt + Shift + F10) 테스트 시 결과가 녹색으로 뜰 경우는 정상, 그렇지 않은 경우 오류가 발생한 것이기 때문에 확인해야 한다. 첫번째이미지 두번째이미지


*출처 : https://jdm.kr/blog/165참고