본문 바로가기
Sparta 내일배움캠프 Java 5기/[최종 프로젝트] 커뮤니티 서비스 Team Project ✓ 2024. 7. 26.

(24.07.26) 코드 리뷰 기능(게시글, 댓글, 좋아요) 테스트 코드 작성

 

통합 테스트 코드 작성

Controller 테스트 코드

  • @WebMvcTest 테스트 코드 진행

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();
  }
}
  • 인증에 대한 UserDetails을 가져와야하기 때문에 기능을 사용하기 위해서 인증인가 Filter를 거치고 있음 -> Filter를 제외시켜주는 작업을 해줄 수 있도록 MockSpringSecurityFilter를 만들어서 테스트 코드에서 사용

WebMvcTest

@WebMvcTest(
    controllers = {CodeReviewsController.class},
    excludeFilters = {
        @ComponentScan.Filter(
            type = FilterType.ASSIGNABLE_TYPE,
            classes = WebSecurityConfig.class
        )
    }
)
class CodeReviewsControllerTest {

  private MockMvc mockMvc;

  private Principal mockPrincipal;

  @Autowired
  private WebApplicationContext context;

  @MockBean
  private CodeReviewsService codeReviewsService;
  
  ...
  
   @BeforeEach
  public void setUp() {
    mockMvc = MockMvcBuilders.webAppContextSetup(context)
        .apply(
            springSecurity(new MockSpringSecurityFilter()))
        .build();
  }

  private void mockUserSetup() {
    Users user = Users.builder()
        .name("testuser")
        .email("test@example.com")
        .password("Test123!")
        .role(RoleEnum.USER)
        .build();

    UserDetailsImpl testUserDetails = new UserDetailsImpl(user);

    mockPrincipal = new UsernamePasswordAuthenticationToken(testUserDetails, "",
        testUserDetails.getAuthorities());
  }
  
  ...
  • 앞서만든MockSpringSecurityFilter 를 사용할 수 있도록 매 테스트에 BeforeEach로 설정
  • 임의로 만든 user -> 이 정보를 담은 testUserDetails과 principal을 사용할 때, 이 UserDetail 정보를 쓸 수 있도록 mockPrincipal 지정
 // when
    MockHttpServletRequestBuilder request = MockMvcRequestBuilders.post("/api/codereviews")
        .contentType(MediaType.APPLICATION_JSON)
        .content(objectMapper.writeValueAsString(codeReviewsRequestDto))
        .principal(mockPrincipal);
  • MockHttpServletRequestBuilder 로 요청을 임의로 만들때 .principal(mockPrincipal) 로 설정 가능

 

일련의 모든 Controller는 해당 작업을 통해 인증을 거친 후 테스트 코드를 작성


Service 테스트 코드

spring:
  datasource:
    url: jdbc:h2:mem:PublicClassDev
    driver-class-name: org.h2.Driver
    username: sa
    password:
  h2:
    console:
      enabled: true
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
  • in memory 를 사용하기 위해서 application-test.yml을 따로 만들어서 활용 가능
@SpringBootTest
@ActiveProfiles("test")
public class CodeReviewsServiceTest {
...
  • 통합테스트를 진행을 해서 저장된 데이터에 대한 비지니스 로직 테스트 코드를 위해서 ActiveProfile을 통해서 인메모리에 해당 작업을 할 수 있도록 세팅
    • 테스트를 위한 DB에 save 작업이 존재

Repository 테스트 코드

@DataJpaTest
@ActiveProfiles("test")
public class CodeReviewsRepositoryTest {
...
  • JpaRepository에서 JPQL을 활용해서 코드가 작성되었기 때문에 JPA 테스트하기 위해 DataJpaTest 테스트 진행
    • EntityManager, JpaRepositories 등 자동으로 설정
    • SpringBootTest와 마찬가지로 Transactional 사용