본문 바로가기

봄보라

Spring Boot 에서 JUnit5 , MockMvc를 이용하여 테스트 진행하기

Spring Boot 기반의 웹 프로그램에서 JUnit5 , MockMvc 를 이용하여 테스트를 진행하는 방법입니다

 

JUnit5 테스트를 위한 기본 소스
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;

@SpringBootTest
@AutoConfigureMockMvc
public class ControllerTest {

  @Autowired
  private MockMvc mvc;

  @Test
  public void callTest() throws Exception{
    - 생략 -
  }

}

 

위에는 가장 기본적인 예제입니다

 

@SpringBootTest 를 선언해서 해당 클래스가 Spring Boot 테스트 진행을 위한 클래스라는걸 선언하고

@AutoConfigureMockMvc 를 통해 Spring Boot 에서 사용되는 여러 설정(@Service 등) 을 사용하도록 선언합니다

 

MockMvc 를 이용해 테스트를 진행하고

@Test 선언을 통해 해당 메소드가 테스트 메소드라고 선언합니다

 

 

 

서버 동작을 위한 프로퍼티 설정
@SpringBootTest(properties = {"classpath:/application.yml", "spring.profiles.active=abcd"})

다음으로 Spring Boot 실행 시 별도의 설정이 필요할 경우 @SpringBootTest 의 properties 속성을 통해 설정할 수 있다

만약 서버 실행 시 -Dspring.profile.active=abcd 라는 설정이 필요하다면 위에처럼 사용할 수 있다

 

 

GET 방식의 호출 JUnit5 테스트
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.result.MockMvcResultMatchers.status;

@Test
@DisplayName("GET 방식 테스트")
public void callGetTest() throws Exception{
  this.mvc.perform(get("/main"))
                   .andExpect(status().isOk());
}

 

브라우저에서 http://도메인/main 이란 URL 을 호출하는 테스트다

응답으로 200 code 가 리턴되면 JUnit5 테스트가 정상 완료된다

이처럼 모든 테스트는 MockMvc 를 이용하여 진행된다

 

 

GET 방식 호출 후 리턴되는 view 이름으로 테스트
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;

@Test
@DisplayName("GET 방식 테스트")
public void callGetTest() throws Exception{
  this.mvc.perform(get("/main"))
                   .andExpect(status().isOk())
                   .andExpect(view().name("main/page"));
}

컨트롤러에서 뷰 이름을 String 타입으로 리턴할 때 테스트하는 방식이다

 

 

Redirect 응답 시 테스트
import static org.springframework.test.web.servlet.result.MockMvcREsultMatchers.redirectedUrl;

@Test
@DisplayName("GET Redirect 방식 테스트")
public void callGetTest() throws Exception{
  this.mvc.perform(get("/main"))
                   .andExpect(status().is3xxRedirection())
                   .andExpect(redirectedUrl("/abcd/efg"));
}

특정 URL 호출 시 경우에 따라 다른 주소로 Redirect 될 때 테스트하는 방식이다

 

 

CSRF 토큰 필요 시 테스트
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;

@Test
@DisplayName("CSRF 토큰 테스트")
public void callCsrfTest() throws Exception{
  this.mvc.perform(post("/main").with(csrf()))
                   .andExpect(status().isOk());
}

내부적으로 Spring Security 를 사용하고 있고 CSRF 토큰을 이용하고 있다면 경우에 따라 CSRF 토큰도 함께 포함해서 요청해야 할 수도 있다. 

만약 csrf() 를 제외할 경우 403 응답으로 수신된다

 

 

JUnit5 요청/결과 내용 보기
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;

@Test
@DisplayName("GET 방식 테스트")
public void callGetTest() throws Exception{
  this.mvc.perform(get("/main"))
                   .andExpect(status().isOk())
                   .andDo(print());
}

테스트 중 JUnit5 에서 어떤식으로 요청을 보냈고 어떤 응답을 받았는지 보고싶을 수 있다

이때 andDo(print()) 를 추가해주면 콘솔에서 확인해볼 수 있다

 

 

트랜잭션 테스트
import org.springframework.transaction.annotation.Transactional;

@Test
@Transactional
@DisplayName("트랜잭션 방식 테스트")
public void callInsertTest() throws Exception{
  this.mvc.perform(post("/add"))
                   .andExpect(status().isOk())
                   .andDo(print());
}

JUnit5 를 이용해 등록/변경 테스트 시 실제로 데이터베이스에 데이터가 등록되거나 변경이 되면 안된다

이럴 경우 @Transactional 를 선언해주면 테스트 완료 후 롤백처리된다

 

 

요청 시 파라미터 추가 방법
@Test
@Transactional
@DisplayName("파라미터 방식 테스트")
public void callInsertTest() throws Exception{
  this.mvc.perform(post("/add")
                                    .param("name", "홍길동")
                                    .param("age", "11"))
                   .andExpect(status().isOk())
                   .andDo(print());
}

JUnit5 를 통해 Get, Post, Put 등의 메소드로 컨트롤러 호출 시 파라미터를 추가할 때가 있다

이때는 param 메소드를 통해 추가하면 된다

 

 

예외 응답 처리
@Test
@Transactional
@DisplayName("예외 발생 테스트")
public void callExceptionTest() throws Exception{
  org.assertj.core.api.Assertions.assertThatThrownBy(()->
       this.mvc.perform(post("/add")
                                    .param("name", "홍길동")
                                    .param("age", "11"))
                   .andExpect(status().isOk())
                   .andDo(print())
    ).hasCause(new NullPointerException());
}

개발자의 구현 방식에 따라 강제로 예외를 발생시키는 경우도 있다

만약 위의 호출에서 NullPointerException 이 발생하는게 정상일 경우 위의 방식처럼 호출하면 된다

만약 NullPointerException 안에 별도의 문구도 있다면 동일하게 문구까지 설정해줘야한다

 

 

로그인이 필요한 요청 호출
import org.springframework.security.test.context.support.WithUserDetails;

@Test
@WithUserDetails(userDetailsServiceBeanName = "testUser")
@Transactional
@DisplayName("로그인 필수 요청 호출 테스트")
public void callInsertTest() throws Exception{
  this.mvc.perform(post("/add")
                                    .param("name", "홍길동")
                                    .param("age", "11"))
                   .andExpect(status().isOk())
                   .andDo(print());
}
@Service
public class testUser implements UserDetailsService{
  @Override
  public UserDetials loadUserByUsername(username) throws UsernameNotFoundException{
    - 생략 -
    return xx;
  }
}

대부분의 요청은 로그인 상태에서만 유효하다

이런 테스트를 위해 @WithUserDetials 를 선언하여 로그인 상태의 서비스를 이용할 수 있다

 

 

여기까지 Spring Boot 환경에서 JUnit5 와 MockMvc 를 이용한 테스트를 마무리한다

 

 

참고 솔루션 : 봄즈