웹 개발/Spring Framework

JUnit에서 Controller 테스트 코드 작성하기(정리)

희랍인 조르바 2018. 6. 18. 13:46


많은 부분을 참조한 출처: http://thswave.github.io/java/2015/03/02/spring-mvc-test.html


맨 먼저 환경설정.


JUnit을 위한 기본적인 환경설정이 돼있다는 전제 하에 


Mock 디펜던시가 필요하다.


아래 소스를 추가.


1
2
3
4
5
6
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.10.19</version>
    <scope>test</scope>
</dependency>
cs



컨트롤러 테스트는 서비스와 잘 연결됐는지 확인만 해주면 되기 때문에


데이터를 받아오는 것까진 굳이 확인해줄 필요없다.

(하는 부분까지 데이터를 받는 게 되지도 않았지만..)


비즈니스 로직은 Service와 DAO에서 확인하면 될 것이다.


먼저, 전체소스부터 보여주고 차례로 정리해보겠다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
@Transactional
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={
      "file:src/main/resources/config/spring/context-*.xml"
})
public class PracticeControllerTest {
    private static final Logger logger = LoggerFactory.getLogger(PracticeControllerTest.class);
 
    @Mock
    SecondTesteService secondTestService;
    
    @Mock
    FirstTestService firstTestService;
    
    @InjectMocks
    private PracticeTestController practiceTestController;
    
    private MockMvc mockMvc;
    
    private LoginDTO loginDTO;
    private Map<String, Object> params;
    private ModelAndView mv;
    
    public MockHttpSession session;
    public MockHttpServletRequest request;
    
    @Before
    public void setUp() throws Exception {
        
        searchParamVO = new SearchParamVO();
        params = new HashMap<>();
        mv = new ModelAndView();
        
        loginDTO = new LoginDTO();
        loginDTO.setGroupSeq("zorbaGroup");
        loginDTO.setCompSeq("zorbaCompany");
        loginDTO.setEmpSeq("1234");
 
        session = new MockHttpSession();
        session.setAttribute("loginDTO", loginDTO);
        
        request = new MockHttpServletRequest();
        request.setSession(session);
        RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));
        
        MockitoAnnotations.initMocks(this);
        mockMvc = MockMvcBuilders.standaloneSetup(practiceTestController).build();
    }
    
    /*
     * 테스트 페이지 뷰
     * */
    @Test
    public void testChocolateView() throws Exception {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("loginDTO", loginDTO);
        
        mockMvc.perform(get("/test/view").session(session)).andExpect(status().isOk())
                                                                  .andExpect(view().name("/test/view/chocolate.jsp"));
        verify(secondTestService).getOPTION(paramMap);
        
        mv = practiceTestController.ChocolateView(searchParamVO, params, request);
        
        assertTrue(mv.getModel().containsKey("optionA")); // return 됐을 때 해당 키를 포함하고 있는지 확인
        assertTrue(mv.getModel().containsKey("optionB"));
        assertTrue(mv.getModel().containsKey("loginDTO"));
        
        verify(secondTestService, times(1)).getOPTION(paramMap);
        verify(secondTestService, atLeastOnce()).getOPTION(paramMap);
    }
    
    /*
     * 테스트 리스트 조회
     * */
    @Test
    public void testGetChocolateList() throws Exception {
        
        mockMvc.perform(get("/test/getChocolateList").session(session)).andExpect(status().isOk()) // 상태 200이 되는지 검증
                                                                     .andExpect(view().name("jsonView")); // 심어준 뷰 검증
        
        mv = practiceTestController.GetChocolateList(params, request);
        
        verify(firstTestService).GetChocolateList(params); // 컨트롤러와 잘 연동되는지 검증
        verify(firstTestService, times(1)).GetChocolateList(params); // 몇 번 호출되는지 검증
        verify(firstTestService, atLeastOnce()).GetChocolateList(params); // 최소한 1번 이상 수행 검증
    }
    
 
}
 
cs



이제부터 하나하나씩 뜯어보겠다.



1
2
3
4
5
6
7
8
    @Mock
    SecondTesteService secondTestService;
    
    @Mock
    FirstTestService firstTestService;
    
    @InjectMocks
    private PracticeTestController practiceTestController;
cs


@Mock@InjectMocks이다.


@InjectMocks에 선언된 컨트롤러에 @Mock에 선언된 Service를 빈으로 주입한다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public MockHttpSession session;
    public MockHttpServletRequest request;
    
    @Before
    public void setUp() throws Exception {
        
        searchParamVO = new SearchParamVO();
        params = new HashMap<>();
        mv = new ModelAndView();
        
        loginDTO = new LoginDTO();
        loginDTO.setGroupSeq("zorbaGroup");
        loginDTO.setCompSeq("zorbaCompany");
        loginDTO.setEmpSeq("1234");
        session = new MockHttpSession();
        session.setAttribute("loginDTO", loginDTO);
        
        request = new MockHttpServletRequest();
        request.setSession(session);
        RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));
cs


Mock세션을 만드는 것은 여기 참조.



1
2
3
MockitoAnnotations.initMocks(this);
 
mockMvc = MockMvcBuilders.standaloneSetup(practiceTestController).build();
cs


MOckitoAnnotations.initMocks(this)이 @Autowired 역할을 수행한다.


standaloneSetup은 컨트롤러를 MockMvc 객체로 등록해준다.


1
2
mockMvc.perform(get("/test/view").session(session)).andExpect(status().isOk())
                                                   .andExpect(view().name("/test/view/chocolate.jsp"));
cs


get방식으로 request를 요청한 것이다. 


.perform()을 이용하면 매핑url로 request한다. request에서 session을 심어주고 싶다면


.session으로 해서 담아주면 되고,


.andExpect를 이용해서 다양하게 검증할 수 있다.


status().isOk()는 상태가 200번을 내뱉는지, 400번 에러를 뱉는지 체크할 수 있고,


내가 담아주려한 view에 정확하게 담겼는지 확인할 수 있다. (그 외에도 다양한 검증방법이 있으니 찾아보면 됨)



1
2
3
4
5
mv = practiceTestController.ChocolateView(searchParamVO, params, request);
        
        assertTrue(mv.getModel().containsKey("optionA")); // return 됐을 때 해당 키를 포함하고 있는지 확인
        assertTrue(mv.getModel().containsKey("optionB"));
        assertTrue(mv.getModel().containsKey("loginDTO"));
cs


Map형식으로 ModealAndView를 리턴할 때 해당 키를 포함하고 있는지 체크하는 방법이다.


ModelAndView.getModel().contatinsKey() 활용




1
2
verify(secondTestService, times(1)).getOPTION(paramMap);
        verify(secondTestService, atLeastOnce()).getOPTION(paramMap);
cs


verify()는 서비스가 컨트롤러에 잘 연동되고 동작하는지 검증하기 위한 메서드로 사용했다.

time(int 값)은 컨트롤러에서 해당 메서드를 몇 번 수행하는지 체크하기 위함이다.

verify(secondTestService, atLeastOnce()) 에서 atLeastOnce()는 

메서드가 한 번 이상 수행했는지 검증해준다.

동작하는지 안하는지만 보고 싶다면 atLeastOnce만 검증해도 될 것 같다.


컨트롤러 테스트 끝~