등장 배경 : 소프트웨어에 대한 개발자의 책임이 높아지는 동시에, 자동화 테스트에 대한 관심이 높아지며 이에 따라 다양한 테스트를 지원하는 프레임워크가 등장했고, 그 중 하나가 JUnit.
xUnit의 Java 버전으로, Java 진영에서 단위 테스트를 작성할 수 있도록 다양한 어노테이션과 메소드를 지원한다.
JUnit은 @Test가 붙은 메소드를 테스트 메소드로 인식하여 이를 추적한다.
해당 테스트 메서드를 자동화된 방법으로 검증하고, GUI를 통해 결과값을 제시한다.
setUp 단계 : @Before 메소드를 실행한다.@Test 단계 : @Test 메소드를 호출하고 테스트 결과를 저장해둔다.tearDown 단계 : @After 메소드를 실행한다.setUp 단계에서 정의한 정보
즉, 테스트를 수행하는 데 필요한 정보나 오브젝트
테스트에서는 픽스처를 정의하는 시점에 따라 테스트의 결과가 달라지기에, 픽스처의 정의 시점이 매우 중요함.
각 메소드 단계 전에 실행할 것인지 (@BeforeEach ), 테스트 클래스가 실행하는 시점에 실행할 것인지 ( @BeforeAll )에 따라 테스트 결과가 다를 수 있어, 이러한 픽스처를 정의하는 시점을 관리하는 것이 매우 중요하다.
JUnit은 픽스처를 관리할 수 있는 테스트 어노테이션을 제공하고 있음.
이러한 테스트 어노테이션이 붙은 메소드를 픽스처 메소드라 부름
( @Before, @After가 붙은 메소드가 이에 속함 )
테스트할 메소드에 @Test 어노테이션을 지정함.
접근제한자는 반드시 public으로 정의함.
리턴 타입은 void로 테스트 메소드는 반환 값이 없음.
? extends Throwable> )@WebMvcTest(BoardController.class)
public class BoardControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private BoardService boardService;
@Test
@DisplayName("MockMvc를 통한 Board 데이터 가져오기")
void getBoardTest() throws Exception {
// given
Long boardId = 123L;
BoardEntity boardEntity = new BoardEntity();
boardEntity.setBseq(boardId);
boardEntity.setTitle("Test Title");
boardEntity.setContents("Test Contents");
boardEntity.setRegid("testuser");
boardEntity.setRegdate(new Date());
given(boardService.svcBoardDetail(boardId)).willReturn(boardEntity);
// andExpect
mockMvc.perform(get("/board_detail/" + boardId))
.andExpect(status().isOk())
.andExpect(view().name("lec06_html/board_detail"))
.andExpect(model().attributeExists("MY_BAORD_VO"))
.andExpect(model().attribute("MY_BOARD_VO", hasProperty("bseq", is(123L))))
.andExpect(model().attribute("MY_BOARD_VO", hasProperty("title", is("Test Title"))))
.andExpect(model().attribute("MY_BOARD_VO", hasProperty("contents", is("Test Contents"))))
.andExpect(model().attribute("MY_BOARD_VO", hasProperty("regid", is("testuser"))))
.andDo(print()); // 응답값 print
verify(boardService).svcBoardDetail(123L);
}
}
MockHttpServletRequest:
HTTP Method = GET
Request URI = /board_detail/123
Parameters = {}
Headers = []
Body = null
Session Attrs = {}
Handler:
Type = com.boot.demo.lec06.BoardController
Method = com.boot.demo.lec06.BoardController#ctlBoardDetail(Model, Long)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = lec06_html/board_detail
View = null
Attribute = MY_BOARD_VO
value = BoardEntity(bseq=123, search_str=null, title=Test Title, contents=Test Contents, regid=testuser, regdate=Tue Jul 30 09:50:47 KST 2024, files=null)
errors = []
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [Content-Language:"en", Content-Type:"text/html;charset=UTF-8"]
Content type = text/html;charset=UTF-8
Body = <!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html"; charset="UTF-8">
<title>게시글 상세</title>
</head>
<body>
<h1>게시글 상세</h1><hr>
...(view 내용들)
Forwarded URL = null
Redirected URL = null
Cookies = []
@WebMvcTest 어노테이션은 무엇일까스프링 부트에서 제공하는 어노테이션 중 하나로, 웹 어플리케이션의 MVC 컨트롤러(Controller)를 테스트하기 위해 사용됩.
특정 컨트롤러를 대상으로 하는 단위 테스트를 작성할 때 사용한다.
웹 레이어에서 발생하는 요청과 응답을 테스트할 수 있음.
컨트롤러 단위 테스트를 할 때는, 무엇을 가짜로 띄울지 결정할 수 있어야하는 것이 중요.
MockMvc 란 무엇일까테스트용 MVC 환경을 만들어, 요청 및 전송 & 응답기능을 제공해주는 유틸리티 클래스
실제 서버로 구현한 어플리케이션을 올리지 않고, 테스트용으로 시뮬레이션하여 MVC가 되도록 도와주는 클래스
1-1. MockMvc 작동 순서
MockMvc 생성 ( @Autowired )MockMvc에게 요청에 대한 정보를 입력이 블로그가 잘 정리되어 있는 게 보여 참조
https://velog.io/@jkijki12/Spring-MockMvc
@MockBean이란 무엇일까SprintBoot 1.4에서 추가된 테스트 어노테이션
테스트 더블?

테스트 범위를 대상코드 자체의 동작과 협력객체와의 연계동작으로만 제한 가능
Mock = 껍데기만 있는 객체
Mock Bean = 기존에 사용되던 Bean의 껍데기만 가져오고, 내부의 구현 부분은 모두 사용자에게 위임한 형태
given 이란 무엇일까import static org.mockito.BDDMockito.given;
해당 Mock Bean이 어떤 행동을 취하면 어떤 결과를 반환한다를 선언하는 부분
given(httpSession.getAttribute("loginUser")).willReturn(customer)
httpSession.getAttribute()를 호출할 때, 파라미터 값이 loginUser 라면,willReturn(customer) : customer를 리턴하라는 의미verify 란 무엇일까.import static org.mockito.Mockito.verify;
스터빙한 메소드가 제대로 실행이 되었는지 확인해보는 메소드
스터빙한 메소드가 실행되었는지, n번 실행되었는지, 실행 시간이 초과되지 않았는지 등을 다양하게 검증해볼 수 있음.
verify(T mock, VerificationMode mode)
VerificationMode는 검증할 값을 정의하는 메소드
@ExtendWith(SpringExtension.class)
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class BoardRepositoryTest{
@Autowired
private BoardRepository boardRepository;
@Autowired
private ReplyRepository replyRepository;
@Test
public void testListBoards() {
BoardEntity board1 = new BoardEntity();
board1.setTitle("Test Title 1");
board1.setContents("Test Contents 1");
board1.setRegid("testuser1");
board1.setRegdate(new Date());
BoardEntity board2 = new BoardEntity();
board2.setTitle("Test Title 2");
board2.setContents("Test Contents 2");
board2.setRegid("testuser2");
board2.setRegdate(new Date());
boardRepository.save(board1);
boardRepository.save(board2);
List<BoardEntity> boards = boardRepository.findAll(Sort.by(Sort.Direction.DESC, "regdate"));
assertThat(boards).hasSizeGreaterThanOrEqualTo(2);
}
@Test
public void testInsertBoard() {
BoardEntity board = new BoardEntity();
board.setTitle("Test Title");
board.setContents("Test Contents");
board.setRegid("testuser");
board.setRegdate(new Date());
BoardEntity savedBoard = boardRepository.save(board);
assertThat(savedBoard.getBseq()).isNotNull();
}
@Test
public void testDetailBoard() {
BoardEntity board = new BoardEntity();
board.setTitle("Test Title");
board.setContents("Test Contents");
board.setRegid("testuser");
board.setRegdate(new Date());
BoardEntity savedBoard = boardRepository.save(board);
Optional<BoardEntity> foundBoard = boardRepository.findById(savedBoard.getBseq());
assertThat(foundBoard).isPresent();
assertThat(foundBoard.get().getTitle()).isEqualTo("Test Title");
}
@Test
public void testUpdateBoard() {
}
}