프로젝트를 진행하면서 테스트 코드를 일부 작성해봤다. 나머지는 팀원 한 분이 맡아서 하셨다.
service 쪽 테스트 코드를 짜봤는데 맞는지 아닌지도 잘 모르겠고, controller 테스트 코드도 있는 것을 안 후로 공부를 조금 해보았다.
@WebMvcTest 를 사용한 이유는 @SpringBootTest 를 사용하면 실제 어플리케이션 설정을 모두 로드하기 때문에 어플리케이션 규모가 커지면 느려지기 때문이다.
build.gradle 에서 확인을 해주자! test할 때 필요하다.
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
tasks.named('test') {
useJUnitPlatform()
}
or 이거 두 개의 차이는 찾아봐야 한다.
test {
useJUnitPlatform()
}
먼저 MVC 패키지 안에 가짜 사용자를 만들어 줘야 한다.
MockSpringSecurityFilter
public class MockSpringSecurityFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
SecurityContextHolder.getContext()
.setAuthentication((Authentication) ((HttpServletRequest) req).getUserPrincipal());
chain.doFilter(req, res);
}
@Override
public void destroy() {
SecurityContextHolder.clearContext();
}
}
그 후 테스트 하고싶은 곳에 간다.
TodoController를 테스트하고 SecurityConfig를 excludeFilters 로 제외시킨다.
그리고 @MockBean을 이용하여 가짜 Bean을 등록시켜준다.
Spring에서 제공해주는 MockMvc 와 Principal도 선언해준다.
ObjectMapper를 통해 Object 형태로 변환을 해줄 수 있고,
WebApplicationContext를 통해 MockMvc를 빌드하게 된다.
mockUserSetup()은 로그인 처리를 해주는 것이다.
이를 위해 MockSpringSecurityFilter 해주고, 모듈도 추가한 것이다.
매 테스트 케이스 마다 this.mockUserSetup();
가 들어간다.
UsernamePasswordAuthenticationToken 안에 UserDetailsImpl이 있었고 그 안에 User가 있다.
최종적으로 만들어진 것을 mockPrincipal 보낼 때 담아서 보내준다.
필터에 대해 좀 더 자세한 Reference - 여기
setup()은 MockSpringSecurityFilter 사용해서 세팅하는데,
SpringSecurity에 가짜 사용자 정보를 넣어주기 위해 Filter 사용해서 Authentication 하는 것이다.
이제 본격적으로 test 코드로 들어가보자!!
먼저 위에서 만들었던 mockUserSetup()을 통해 로그인 처리를 해준다.
그 후 Dto 데이터 형식에 맞춰서 데이터를 집어 넣는다.
objectMapper를 통해 Object 형식으로 변환을 해준다.
/api/todos로 요청을 보내고, json 형태를 담은 string 변수를 content
에 넣는다.(HTTP Body 부분)
.contentType
으로 type을 맞춰주고 .accept
를 통하여 Json으로 받을 수 있다고 서버에게 알려준다.
.andExpect
를 통해 응답값이 200 나오면 정상인 것이다.
그 후 verify 를 통해 검증을 해준다.
안에 인자를 보면 해당 api에서 사용한 service를 적어준 후, 메소드 명도 적어준다.
그 후 들어가는 파라미터에 맞게 적어주면 되는데
만약 인자가 Long 타입이면 anyLong()을 적어주면 된다!
추가 사진
api에 파라미터가 들어가있는 경우에는 , [숫자] 를 적어주면 된다.
response 값이 없다면 content, contenttype, accept는 생략이다!
이제 service 쪽 코드도 보자!
Mockito에서 제공하는 목 객체를 사용하기 위해 @ExtendWith(MockitoExtension.class)
를 달아준다.
그 후 @Mock, @Spy와 @InjectMock을 통하여 Mock 객체를 만들어준다.
@Mock - 빈 껍데기, @Spy - 모든 기능을 가지는 완전한 객체
Spring Boot Container가 테스트 시에 필요하고, Bean이 Container에 존재한다면 @MockBean을 사용하고 아닌 경우에는 @Mock을 사용한다는 데 아직 구별을 잘 못하겠다,,
셋업에 필요한 변수들과 생성자를 생성해준다 쭉!!!
setUp()에서 테스트 코드 실행 전 들어가야 할 내용들을 설정해준다.
todoService = new TodoService( );
안에는 todoService에서 사용하는 bean 객체들을 넣어주면 된다.
todoRegisterDto 데이터 형식에 맞춰 넣어준다. 그 후 service단에 있는 메소드를 실행시킨 결과를 result에 담고 assertEquals로 비교해준다.
만약 실패 testcase를 넣고 싶다면?
//when
CustomException exception = Assertions.assertThrows(CustomException.class,
() -> todoService.registerTodo(todoRegisterDto, userDetails));
//then
Assertions.assertEquals("친구와 먼저 매칭을 먼저 해주세요."
,exception.getErrorCode().getMessage());
이런식으로 해주면 된다!
다음은 given 이다. todoRepository에 있는 findById가 실행되었을 때 기댓값을 뒤에 willReturn에 넣어주면 된다.
given 안에 들어있는 두 매소드는 confirmTodo에 있다.
탑건 4dx로 보고싶다 탑건