티스토리 뷰

 

[ 1 . MockMVC ] (*****)

 

더보기

[ + 코드 보기 ]

package org.zerock.myapp.controller;

import java.util.concurrent.TimeUnit;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MockMvcBuilder;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.ui.ModelMap;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.ModelAndView;

import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;

@Log4j2
@NoArgsConstructor

// JUNIT 5
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = { 
						"file:src/main/webapp/WEB-INF/spring/root-context.xml",
						"file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml"})

@TestInstance(Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)

// + Spring MVC Controller를 테스트 하기 위해서는
// + 반드시 아래의 어노테이션을 붙여야 한다.
@WebAppConfiguration // (****)
public class BoardControllerTests {
	
	@Autowired
	private WebApplicationContext ctx; 
	// + WebApplicationContext는 스프링 빈즈 컨테이너의 구현 객체이다. (***)
	// + 컨트롤러를 테스트 하기 위해서는 스프링 빈즈 컨테이너를 주입 받아야 한다.
	
	// ===========================================================================
	
	@BeforeAll
	public void beforeAll() {
		log.trace("beforeAll() invoked.");
	} // beforeAll
	
	// ===========================================================================
	
	//@Disabled
	@Test
	@Order(1)
	@DisplayName("1.testList")
	@Timeout(value=5, unit = TimeUnit.SECONDS)
	public void testList() throws Exception {
		log.trace("testList() invoked.");
		
		// ===========================================================================
		// + 표현계층의 사용자 정의 Controller에 대한 테스트를 수행 시, 핵심은 WAS 구동 없이 테스트 필요 :
		// + (1) @WebAppConfiguration 어노테이션
		// + (2) MockMVC 클래스( 가상의 웹 브라우저 ) 사용법 :
		// +	가. Spring Bean Container( WebApplicationContext를 주입받아야 한다. )
		// + 	나. '가'의 주입받은 객체를 이용해서, MockMvcBuilder 객체를 우선 생성
		// + 	다. '나'의 MockMvcBuilders란 Helper Class의 정적 메소드를 이용하여, MockMvcBuilder 객체를 얻는다.
		// + 	라. '다'에서 얻은 MockMvcBuilder.build() 메소드를 통해 MockMvc 객체를 얻는다.
		// + 	마. 'MockMvcBuilders' Helper Class의 정적 메소드를 이용해서, MockMvcRequestBuilder 객체를 얻는다.
		// + 	바. 'MockMvc'와 '마'에서 얻어낸, 'MockMvcRequestBuilder' 2개의 객체를 가지고 실제 가상의 요청(request)을 전송
		// +		- MockMvc.perform(MockMvcRequestBuilder) 메소드 호출로 수행
		// + 		- 테스트 대상인 Controller의 핸들러 메소드가 수행되면서,
		// + 		- 그 결과로 2가지의 정보를 얻게 된다. ( 1. Model 2. 뷰이름 )
		// + 	사. '바'에서 얻은 2가지 정보 중 필요로 하는 정보를 얻어내서 사용
		// ===========================================================================
		// + MockMvcBuilders는 MockMvcBuilder의 헬퍼 클래스이다.
		// + MockMvcBuilder는 MockMvc를 만들어 주는 건설사이다.
		// + MockMvcRequestBuilders.post로 하면 전송방식을 post라고 지정해줄 수 있다.
		// ===========================================================================
		
		// ===========================================================================
		// + 단계별로 연습 : 
		
		// 1 단계 : 스프링 Beans Container의 주소로 얻은 MockMvcBuilder의 정적메소드로 'MockMvcBuilder' 객체 획득
		MockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(ctx);
		
		// 2 단계 : 'MockMvcBuilder' 객체로부터 build해서, 지금 반드시 필요한 핵심객체인 'MockMvc' 객체를 획득
		MockMvc mock = builder.build();
		
		// 3 단계 : 실제 'MockMvc' 객체로 요청( request )을 만들어내려면, 'RequestBuilder' 객체가 우선 필요하다.
		// + 		'MockMvcRequestBuilders' Helper Class의 메소드를 이용하여 'RequestBuilder' 객체 획득
		// + 		( 전송방식 : GET , Request Mapping URI : /board/list인 요청을 만들어내는 RequestBuilder 객체 획득 )
		MockHttpServletRequestBuilder builder2 = MockMvcRequestBuilders.get("/board/list");
		
		// 4 단계 : 위 2단계에서 얻어낸 'MockMvc' 객체와 3단계에서 얻어낸 'RequestBuilder'객체, 2개를 이용하여 실제 요청 전송
		ResultActions resultActions = mock.perform(builder2);
		
		// 5 단계 : 호출된 Controller의 Handler 메소드에서 반환된 2개의 데이터 ( 뷰이름 + Model )를 추출
		// +		Controller Handler 메소드가 실행종료되어 2개의 데이터를 반환할 때까지 기다린다.
		MvcResult mvcResult = resultActions.andReturn();
		
		// 6 단계 : 'MvcResult'가 가지고 있는 2가지 데이터를 한꺼번에 'ModelAndView' 객체로 얻어냄
		ModelAndView resultData = mvcResult.getModelAndView();
		
		// 7 단계 : 'ModelAndView'에서 각각 'Model'과 'View' 객체를 얻어낼 수 있다.
		String viewName = resultData.getViewName();
		ModelMap model = resultData.getModelMap();
		HttpStatus statusCode = resultData.getStatus();
		
		// 8 단계 : 확인하기 ( 상태 코드는 아직 지정해주지 않았기에 null이다. )
		log.info("\t + viewName : {}", viewName);		// + viewName : board/list
		log.info("\t + model : {}", model);				// + model : {__LIST__=[BoardVO(....)]}
		log.info("\t + statusCode : {}", statusCode);	// + statusCode : null
		
		// ===========================================================================
		
		// + 축약형 ( 메소드 체이닝 ) (******)
		
		MockMvcBuilder mockMvcBuilder = MockMvcBuilders.webAppContextSetup(ctx);
		MockMvc mockMvc = mockMvcBuilder.build();
		
		// + 요청 ( 전송방식 : GET , Request Mapping URI : /board/list )
		RequestBuilder reqBuilder = MockMvcRequestBuilders.get("/board/list");
		
		// + ModalMap의 실제 타입 => LinkedHashMap<String, ArrayList> (****)
		ModelMap modelMap = mockMvc.
									perform(reqBuilder).			// + 요청을 보내고
									andReturn().					// + 리턴을 기다리겠다. ( MvcResult )
									getModelAndView().				// + 모델과 뷰를 얻어내겠다. ( ModelAndView )
									getModelMap();					// + 그 중에서 모델만 달라 ( ModelMap )
		
		// -------------------------------------------------------------------------------------------
		
		modelMap.forEach((t, u) -> {
			log.info("\t + t : {}", t);
			log.info("\t + u : {}", u);
		}); // forEach
		
		// + 자원 해제 : Map Clear + Map객체 저장 참조변수 값을 null로 지정 -> 빠른 GC가 가능
		modelMap.clear();
		modelMap = null;
		
	} // testList
	
	// ===========================================================================

} // end class

[ 2. MockMvc 적용 - VO객체를 DTO로 변경 ] (****)

 

[ 2 - 1. Controller 생성 ]

 

더보기

[ + 코드 보기 ]

package org.zerock.myapp.controller;

import java.util.List;
import java.util.Objects;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.zerock.myapp.domain.BoardDTO;
import org.zerock.myapp.domain.BoardVO;
import org.zerock.myapp.exception.ControllerException;
import org.zerock.myapp.service.BoardService;

import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;


@Log4j2
@NoArgsConstructor

@Controller
@RequestMapping("/board/*")	// 기본 URI
public class BoardController implements InitializingBean {
	
	// + Bean 의존성 주입
	// + 자동 의존성 주입 발생 : (1) 주입받을 필드가 1개 (2) 이 필드를 매개변수로 가지는 생성자
	// + 위와 같은 상황일 때에는 따로 주입 시그널을 보내지 않아도 자동으로 주입된다.
	@Setter(onMethod_= {@Autowired})
	private BoardService boardService;
	
	// ===============================================
	// + 1. 게시판 목록조회 요청 처리 핸들러 메소드 
	// ===============================================
	
	// @ResponseStatus(code = HttpStatus.OK) : 컨트롤러 메소드 테스트 수행시 오류를 발생시킬 수 있다.
	@GetMapping("/list")	// 상세 URI
	public void list (Model model) throws ControllerException {
		log.info("list({}) invoked.", model);
		
		try {
			
			// + 목록 조회하는 service
			List<BoardVO> list = this.boardService.getAllList();
			
			// + 아래와 같은 방법 외에도 model이 아닌 Map으로 받아서, 
			// + model에 저장하는 것이 아니라 Map에 저장하는 방법도 있다.
			// Map<String, Object> map = new HashMap<>();
			// map.put("__LIST__", list);
			
			// + 리스트가 비어있지 않을 때 model로 바인딩
			if ( list != null ) {
				
				model.addAttribute("__LIST__",list);
				// + model은 Request Scope에 저장하게 되는데,
				// + 이때 공유 영역에서는 NULL을 저장하지 않는다.
				// + 그렇기에 이 경우 사실 if문은 필요 없다.
				
				list.forEach(log::info);
				
			} // if
			
		} catch(Exception e) {
			throw new ControllerException(e);
		} // try - catch : ServiceException을 ControllerException으로
		
	} // list
	
	// ===============================================
	// + 2. 새로운 게시물 등록 처리 요청 메소드 (***)
	// ===============================================
	// + 단순 View 호출은 GET방식, 
	// + 비지니스 처리를 하기 위해서는 Post로 해야 한다.
	// ===============================================
	// + 전송파라미터를 객체로 얻어내면, Spring에서 이것을 Command Object라고 부르며
	// + Model을 사용하지 않아도 자동으로 View까지 전송된다. (***)
	// ===============================================
	
	@PostMapping("/register")
	public String register (BoardDTO dto, RedirectAttributes rttrs) throws ControllerException {
		
		log.trace("\t register({}, {}) invoked.", dto, rttrs);
		
		try {
			
			// + 필드에 주입받은 서비스 객체의 메소드 호출 -> 핵심 메소드 호출
			if ( this.boardService.add(dto) == 1 ) {
				rttrs.addAttribute("__RESULT__", "success");
			} else {
				rttrs.addAttribute("__RESULT__", "failed");
			} // if - else
			
			// + 업데이트 한 후에는 전체 목록 조회 페이지로 이동해야 한다. (***)
			return "redirect:/board/list";
			
		} catch(Exception e) { 
			throw new ControllerException (e);
		} // try - catch
		
	} // register
	
	// ===============================================
	
	@PostMapping("/register2")
	public String register2 (BoardDTO dto, RedirectAttributes rttrs) throws ControllerException {
		
		log.trace("\t register2({}, {}) invoked.", dto, rttrs);
		
		try {
			
			// + 필드에 주입받은 서비스 객체의 메소드 호출 -> 핵심 메소드 호출
			if ( this.boardService.addAuto(dto) ) {
				
				rttrs.addAttribute("__RESULT__", "success");
				
				// rttrs.addFlashAttribute("__RESULT__", "success");
				// + addFlashAttribute도 Request Scope을 통해 전달은 가능하지만, 추천하지는 x
				
			} else {
				rttrs.addAttribute("__RESULT__", "failed");
			} // if - else
			
			// + 업데이트 한 후에는 전체 목록 조회 페이지로 이동해야 한다. (***)
			return "redirect:/board/list";
			
		} catch(Exception e) { 
			throw new ControllerException (e);
		} // try - catch
		
	} // register
	
	// ===============================================
	// + 3. 게시판에 특정 게시물 삭제 요청 메소드
	// ===============================================
	
	@PostMapping("/remove")
	public String remove( BoardDTO dto, RedirectAttributes rttrs ) throws ControllerException {
		
		log.info("remove({}, {}) invoked.", dto, rttrs );
		
		try {
			
			if ( this.boardService.remove(dto) == 1 ) {
				rttrs.addAttribute("__RESULT__", "success");
			} else {
				rttrs.addAttribute("__RESULT__", "failed");
			} // if - else
			
			return "redirect:/board/list";
			
		} catch(Exception e) {
			throw new ControllerException (e);
		} // try - catch
		
	} // remove
	
	// ===============================================
	// + 4. 새로운 게시물 수정 요청 메소드
	// ===============================================
	
	@PostMapping("/update")
	public String update ( BoardDTO dto, RedirectAttributes rttrs ) throws ControllerException {
		
		log.info("update({}, {}) invoked.", dto, rttrs);
		
		try {
			
			if ( this.boardService.update(dto) ) {
				rttrs.addAttribute("__RESULT__", "success");
			} else {
				rttrs.addAttribute("__RESULT__", "failed");
			} // if - else
			
			return "redirect:/board/list";
			
		} catch (Exception e) { throw new ControllerException (e); } // try - catch
		
	} // update
	
	// ===============================================
	// + 선처리
	// ===============================================
	@Override
	public void afterPropertiesSet() throws Exception {
		
		log.trace("afterPropertiesSet() invoked.");
		
		// 필드에 의존성이 잘 주입 되었는지 확인한다.
		Objects.requireNonNull(this.boardService);
		log.info("\t + this.boardService : {}", this.boardService);
		
	} // afterPropertiesSet

} // end class

 

[ 2 - 2. view 생성 ]

 

더보기

[ + 코드 보기 ]

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>View - bord/list.jsp</title>

    <script>

        var result = "${ param.__RESULT__ }";
        console.log(`result : ${result}`);

        if ( result != null && result.length > 0 ) {
            alert('${ param.__RESULT__ }');
        } //if

    </script>

</head>

<body>

    <h1>/WEB-INF/views/bord/list.jsp</h1>
    <hr>

    <h1> I AM bord/list!!!</h1>
    
    <h7> ${__LIST__}</h7>
    
</body>

</html>

 

[ + Test - MockMvc ]

 

더보기

[ + 코드 보기 ]

package org.zerock.myapp.controller;

import java.util.concurrent.TimeUnit;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MockMvcBuilder;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.ui.ModelMap;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.ModelAndView;

import lombok.NoArgsConstructor;
import lombok.extern.log4j.Log4j2;

@Log4j2
@NoArgsConstructor

// JUNIT 5
@ExtendWith(SpringExtension.class)
@ContextConfiguration(locations = { 
						"file:src/main/webapp/WEB-INF/spring/root-context.xml",
						"file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml"})

@TestInstance(Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)

// + Spring MVC Controller를 테스트 하기 위해서는
// + 반드시 아래의 어노테이션을 붙여야 한다.
@WebAppConfiguration // (****)
public class BoardControllerTests {
	
	@Autowired
	private WebApplicationContext ctx; 
	// + WebApplicationContext는 스프링 빈즈 컨테이너의 구현 객체이다. (***)
	// + 컨트롤러를 테스트 하기 위해서는 스프링 빈즈 컨테이너를 주입 받아야 한다.
	
	// ===========================================================================
	
	@BeforeAll
	public void beforeAll() {
		log.trace("beforeAll() invoked.");
	} // beforeAll
	
	// ===========================================================================
	// 1. 게시물 목록 전체 조회
	// ===========================================================================
	
	@Disabled
	@Test
	@Order(1)
	@DisplayName("1.testList")
	@Timeout(value=5, unit = TimeUnit.SECONDS)
	public void testList() throws Exception {
		log.trace("testList() invoked.");
		
		// ===========================================================================
		// + 표현계층의 사용자 정의 Controller에 대한 테스트를 수행 시, 핵심은 WAS 구동 없이 테스트 필요 :
		// + (1) @WebAppConfiguration 어노테이션
		// + (2) MockMVC 클래스( 가상의 웹 브라우저 ) 사용법 :
		// +	가. Spring Bean Container( WebApplicationContext를 주입받아야 한다. )
		// + 	나. '가'의 주입받은 객체를 이용해서, MockMvcBuilder 객체를 우선 생성
		// + 	다. '나'의 MockMvcBuilders란 Helper Class의 정적 메소드를 이용하여, MockMvcBuilder 객체를 얻는다.
		// + 	라. '다'에서 얻은 MockMvcBuilder.build() 메소드를 통해 MockMvc 객체를 얻는다.
		// + 	마. 'MockMvcBuilders' Helper Class의 정적 메소드를 이용해서, MockMvcRequestBuilder 객체를 얻는다.
		// + 	바. 'MockMvc'와 '마'에서 얻어낸, 'MockMvcRequestBuilder' 2개의 객체를 가지고 실제 가상의 요청(request)을 전송
		// +		- MockMvc.perform(MockMvcRequestBuilder) 메소드 호출로 수행
		// + 		- 테스트 대상인 Controller의 핸들러 메소드가 수행되면서,
		// + 		- 그 결과로 2가지의 정보를 얻게 된다. ( 1. Model 2. 뷰이름 )
		// + 	사. '바'에서 얻은 2가지 정보 중 필요로 하는 정보를 얻어내서 사용
		// ===========================================================================
		// + MockMvcBuilders는 MockMvcBuilder의 헬퍼 클래스이다.
		// + MockMvcBuilder는 MockMvc를 만들어 주는 건설사이다.
		// + MockMvcRequestBuilders.post로 하면 전송방식을 post라고 지정해줄 수 있다.
		// ===========================================================================
		
		// ===========================================================================
		// + 단계별로 연습 : 
		
		// 1 단계 : 스프링 Beans Container의 주소로 얻은 MockMvcBuilder의 정적메소드로 'MockMvcBuilder' 객체 획득
		MockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(ctx);
		
		// 2 단계 : 'MockMvcBuilder' 객체로부터 build해서, 지금 반드시 필요한 핵심객체인 'MockMvc' 객체를 획득
		MockMvc mock = builder.build();
		
		// 3 단계 : 실제 'MockMvc' 객체로 요청( request )을 만들어내려면, 'RequestBuilder' 객체가 우선 필요하다.
		// + 		'MockMvcRequestBuilders' Helper Class의 메소드를 이용하여 'RequestBuilder' 객체 획득
		// + 		( 전송방식 : GET , Request Mapping URI : /board/list인 요청을 만들어내는 RequestBuilder 객체 획득 )
		MockHttpServletRequestBuilder builder2 = MockMvcRequestBuilders.get("/board/list");
		
		// 4 단계 : 위 2단계에서 얻어낸 'MockMvc' 객체와 3단계에서 얻어낸 'RequestBuilder'객체, 2개를 이용하여 실제 요청 전송
		ResultActions resultActions = mock.perform(builder2);
		
		// 5 단계 : 호출된 Controller의 Handler 메소드에서 반환된 2개의 데이터 ( 뷰이름 + Model )를 추출
		// +		Controller Handler 메소드가 실행종료되어 2개의 데이터를 반환할 때까지 기다린다.
		MvcResult mvcResult = resultActions.andReturn();
		
		// 6 단계 : 'MvcResult'가 가지고 있는 2가지 데이터를 한꺼번에 'ModelAndView' 객체로 얻어냄
		ModelAndView resultData = mvcResult.getModelAndView();
		
		// 7 단계 : 'ModelAndView'에서 각각 'Model'과 'View' 객체를 얻어낼 수 있다.
		String viewName = resultData.getViewName();
		ModelMap model = resultData.getModelMap();
		HttpStatus statusCode = resultData.getStatus();
		
		// 8 단계 : 확인하기 ( 상태 코드는 아직 지정해주지 않았기에 null이다. )
		log.info("\t + viewName : {}", viewName);		// + viewName : board/list
		log.info("\t + model : {}", model);				// + model : {__LIST__=[BoardVO(....)]}
		log.info("\t + statusCode : {}", statusCode);	// + statusCode : null
		
		// ===========================================================================
		
		// + 축약형 ( 메소드 체이닝 ) (******)
		
		MockMvcBuilder mockMvcBuilder = MockMvcBuilders.webAppContextSetup(ctx);
		MockMvc mockMvc = mockMvcBuilder.build();
		
		// + 요청 ( 전송방식 : GET , Request Mapping URI : /board/list )
		RequestBuilder reqBuilder = MockMvcRequestBuilders.get("/board/list");
		
		// + ModalMap의 실제 타입 => LinkedHashMap<String, ArrayList> (****)
		ModelMap modelMap = mockMvc.
									perform(reqBuilder).			// + 요청을 보내고
									andReturn().					// + 리턴을 기다리겠다. ( MvcResult )
									getModelAndView().				// + 모델과 뷰를 얻어내겠다. ( ModelAndView )
									getModelMap();					// + 그 중에서 모델만 달라 ( ModelMap )
		
		// -------------------------------------------------------------------------------------------
		
		modelMap.forEach((t, u) -> {
			log.info("\t + t : {}", t);
			log.info("\t + u : {}", u);
		}); // forEach
		
		// + 자원 해제 : Map Clear + Map객체 저장 참조변수 값을 null로 지정 -> 빠른 GC가 가능
		modelMap.clear();
		modelMap = null;
		
	} // testList
	
	// ===========================================================================
	// 2. 새로운 게시물 등록
	// ===========================================================================
	
	// @Disabled
	@Test
	@Order(2)
	@DisplayName("2.testRegister")
	@Timeout(value=5, unit = TimeUnit.SECONDS)
	public void testRegister() throws Exception {
		
		log.trace("testRegister() invoked.");
		
		MockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(ctx);
		MockMvc mockMvc = builder.build();
		
		MockHttpServletRequestBuilder reqBuilder = MockMvcRequestBuilders.post("/board/register");
		
		// + 필요한 전송파라미터를 설정 ( Lvalue 타입으로 구현타입을 지정해야 한다. )
		reqBuilder.param("bno", "54321");
		reqBuilder.param("title", "TITLE_NEW!!!!!!!!");
		reqBuilder.param("content", "CONTENT_NEW!!!!");
		reqBuilder.param("writer", "WRITER_NEW!!!!!");
		
		String viewName = mockMvc.perform(reqBuilder).andReturn().getModelAndView().getViewName();
		
		log.info("\t + viewName : {}", viewName);
				
	} // testRegister
	
	// ===========================================================================
	// 3. 게시물 삭제 하기
	// ===========================================================================
	
	// @Disabled
	@Test
	@Order(3)
	@DisplayName("3.testDelete")
	@Timeout(value=5, unit = TimeUnit.SECONDS)
	public void testDelete() throws Exception {
		
		log.trace("testDelete() invoked.");
		
		MockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(ctx);
		MockMvc mockMvc = builder.build();
		
		MockHttpServletRequestBuilder reqBuilder = MockMvcRequestBuilders.post("/board/remove");
		
		// + 필요한 전송파라미터를 설정 ( Lvalue 타입으로 구현타입을 지정해야 한다. )
		reqBuilder.param("bno", "54321");
		
		String viewName = mockMvc.perform(reqBuilder).andReturn().getModelAndView().getViewName();
		
		log.info("\t + viewName : {}", viewName);
				
	} // testDelete
	
	// ===========================================================================
	// 4. 게시물 수정하기
	// ===========================================================================
	
	// @Disabled
	@Test
	@Order(4)
	@DisplayName("4. testUpdate")
	@Timeout(value = 5, unit = TimeUnit.SECONDS)
	public void testUpdate() throws Exception {
		
		log.trace("testUpdate() invoked.");
		
		MockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(ctx);
		MockMvc mockMvc = builder.build();
		
		MockHttpServletRequestBuilder reqBuilder = MockMvcRequestBuilders.patch("/board/update");
		
		reqBuilder.param("bno", "898989");
		reqBuilder.param("title", "TITLE_NEW!!!!!!!!");
		reqBuilder.param("content", "CONTENT_NEW!!!!");
		reqBuilder.param("writer", "WRITER_NEW!!!!!");
		
		String viewName = mockMvc.perform(reqBuilder).andReturn().getModelAndView().getViewName();
		
		log.info("\t + viewName : {}", viewName);
		
	} // testUpdate

} // end class

 

 

 

728x90
댓글
«   2024/09   »
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
최근에 올라온 글
Total
Today
Yesterday
공지사항