ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring boot] Java 테스트 코드
    프로젝트/뉴스타 2024. 6. 17. 10:27

    Java 테스트 코드 왜 궁금했을까❓

    뉴스타 서비스에서는 테스트 코드를 작성하여 서비스의 코드 품질을 높이고 장애를 사전에 방지하고자 작성해보려고 한다. 또한, 코드 수정 시 빠르게 검증하여 작업의 생산성을 향상시키고자 한다.

     

    1. 단위 테스트  / 통합 테스트

    1.1. 단위 테스트 (Unit Test)

    • 하나의 기능 또는 함수를 기준으로 독립적으로 수행하는 가장 작은 단위의 테스트
    • 하나의 기능이 정상적으로 동작하는지를 테스트하는 것으로 "어떤 기능이 실행되면 어떤 결과가 나온다" 정도로 테스트한다.

    1.2. 단위 테스트 장점

    1. 테스트에 대한 시간과 비용을 절감
    2. 새로운 기능을 추가하거나 수정 시 빠른 테스트 가능
    3. 리팩토링 시에 안정성 확보
    4. 코드에 대한 문서화

    1.3. 통합 테스트 (Integration Test)

    • 하나의 기능 또는 함수를 통합하는 과정에서 상호 간의 호환성을 확인하기 수행하는 테스트
    • 어플리케이션의 여러 개의 모듈로 구성되어 있는데, 모듈 간의 상호 연계가 잘 되어 동작하는지 검증하는 것이다.
    • 클라이언트로부터 API를 호출하여 올바르게 동작하는지 정도로 테스트한다.

    1.4. 통합 테스트 장점

    1. 컴포넌트 간의 상호작용이 올바르게 동작하는지 확인 가능
    2. API 및 서비스 유효성을 검사 가능

     

    2. 프로젝트 적용

    테스트는 given-when-then 패턴으로 작성하여 가독성을 높일 수 있다. 테스트 코드는 문서의 역할도 하기 때문에 가독성은 중요하다고 할 수 있다.
    • JUnit과 Mockito를 활용하여 통합 테스트를 진행하려고 한다.
    @SpringBootTest
    @AutoConfigureMockMvc(addFilters = true)
    class MemberControllerTest {
      ...
      @Test
      void matchingMember() throws Exception {
        // given
        // when
        mockMvc.perform(get("/members")
                .header("X-User-Id", "feb91399-aaf3-40ef-856d-35e6ddf8befb")) // 사용자 헤더
            // then
            .andExpect(status().isOk())
            .andExpect(content().contentType("application/json"))
            .andExpect(jsonPath("$.statusCode").value(200))
            .andExpect(jsonPath("$.statusName").value("OK"))
            .andExpect(jsonPath("$.message").value("OK"))
            .andExpect(jsonPath("$.data.pw").value("feb91399-aaf3-40ef-856d-35e6ddf8befb"))
            .andExpect(jsonPath("$.data.signDate").exists());
      }
    
      @Test
      void createMember() throws Exception {
        // given
        // when
        mockMvc.perform(post("/members")
                .contentType(MediaType.APPLICATION_JSON) // Content-Type 헤더
                .content("{\"categories\":[100, 200, 300]}"))
            // then
            .andExpect(status().isCreated())
            .andExpect(content().contentType("application/json"))
            .andExpect(jsonPath("$.statusCode").value(201))
            .andExpect(jsonPath("$.statusName").value("CREATED"))
            .andExpect(jsonPath("$.message").value("Created Success"))
            .andExpect(jsonPath("$.data.pw").exists())
            .andExpect(jsonPath("$.data.signDate").exists());
      }
    }
    • 유저 조회와 유저 생성에 대한 통합 테스트를 진행하고 있다.
    • perform()을 통해 HTTP 요청을 실행하고 andExpect()를 통해 Response를 검증한다.
    @SpringBootTest
    @AutoConfigureMockMvc(addFilters = true)
    class RecordControllerTest {
      ...
      @Test
      void getRecords() throws Exception {
        //given
        //when
        mockMvc.perform(get("/records")
                .header("X-User-Id", "feb91399-aaf3-40ef-856d-35e6ddf8befb"))
            //then
            .andExpect(status().isOk())
            .andExpect(content().contentType("application/json"))
            .andExpect(jsonPath("$.statusCode").value(200))
            .andExpect(jsonPath("$.statusName").value("OK"))
            .andExpect(jsonPath("$.message").value("OK"));
      }
    
      @Test
      void getRecordLikes() throws Exception {
        //given
        //when
        mockMvc.perform(get("/records/likes")
                .header("X-User-Id", "feb91399-aaf3-40ef-856d-35e6ddf8befb"))
            //then
            .andExpect(status().isOk())
            .andExpect(content().contentType("application/json"))
            .andExpect(jsonPath("$.statusCode").value(200))
            .andExpect(jsonPath("$.statusName").value("OK"))
            .andExpect(jsonPath("$.message").value("OK"));
      }
    
      @Test
      void createRecord() throws Exception {
        //given
        //when
        mockMvc.perform(post("/records")
                .header("X-User-Id", "feb91399-aaf3-40ef-856d-35e6ddf8befb")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{\"articleId\":1}"))
            //then
            .andExpect(status().isCreated())
            .andExpect(content().contentType("application/json"))
            .andExpect(jsonPath("$.statusCode").value(201))
            .andExpect(jsonPath("$.statusName").value("CREATED"))
            .andExpect(jsonPath("$.message").value("Created Success"));
      }
    
      @Test
      void updateRecordLikes() throws Exception {
        //given
        //when
        mockMvc.perform(patch("/records")
                .header("X-User-Id", "feb91399-aaf3-40ef-856d-35e6ddf8befb")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{\"articleId\":1 , \"likes\":true }"))
    
            //then
            .andExpect(status().isOk())
            .andExpect(content().contentType("application/json"))
            .andExpect(jsonPath("$.statusCode").value(200))
            .andExpect(jsonPath("$.statusName").value("OK"))
            .andExpect(jsonPath("$.message").value("OK"));
      }
    }
    • 뉴스 시청 기록 API에 대해 통합 테스트 코드를 작성해보았다.
    • 이 외에도 위와 같은 형식으로 API 테스트를 진행했다.
Designed by Tistory.