개발을 위한 테스트 가볍게 훑어보기

spaghetti·2024년 4월 17일
0

테스트코드 짜기

목록 보기
1/2

테스트 코드의 필요성은 알고 있었지만 작은 프로젝트들만 진행하다보니 발만 걸치는 느낌으로 했었다. 대규모 트래픽이 발생할 일이 없어서 성능 테스트라는 말도 잘 와닿지 않았어서 자꾸 넘겨버리게 되었는데 이번에 직접 해보면서 필요성을 느껴보고자 정리했다. 이론적인 부분 위주로 정확하게 정리한다기 보다 실무에서 어떤 도구를 이용하고 어떠한 방식으로 사용되는지 알아보려고 한다.


단위테스트

테스트 가능한 가장 작은 소프트웨어를 실행하여 예상대로 동작하는지 확인하는 테스트로 보통은 클래스 또는 메소드 수준으로 테스트한다.

  • 키워드 : Junit / Spock, Mockito, @WebMvcTest, TDD

좋은 단위테스트는 가볍고, 빨라야하고 서로 독립적이야 한다는 특징이있다.
웹 mvc의 경우 보통 레이어(ex. controller)를 나눠서 테스트 코드를 짠다. 빠르고 독립적인 테스트를 위해서는 실제 데이터나 리소스들을 연결하기보다 가짜 데이터를 이용하는데, 이때 mockito라는 라이브러리를 사용한다.

⌨️코드예시

@WebMvcTest(InfoApi.class)
@ExtendWith(MockitoExtension.class)
@Slf4j
class InfoApiTest {

  @Autowired
  private MockMvc mockMvc;

  @MockBean
  private InfoService infoService; //(1)

  @MockBean
  IpAccessInterceptor ipAccessInterceptor;

  @BeforeEach
  void init() throws Exception {
    given(ipAccessInterceptor.preHandle(any(), any(), any()))
        .willReturn(true);
  }


  @DisplayName("정보 가져오기")
  @WithMockUser(username = "admin", roles = {"ADMIN"})
  @Test
  void getInfoTest() throws Exception {
    // given
    InfoDTO dto = InfoDTO.builder()
        .infoId("TEST-01")
        .infoName("제목")
        .address("서울시 강남구")
        .build();

    // when
    Long infoNo = 1L;
    Mockito.doReturn(dto).when(infoService).getInfo(anyLong()); //(2)

    //then
    MvcResult mvcResult = this.mockMvc.perform(
        get("/api/v1/info/{infoNo}", infoNo)
    ).andDo(print()).andReturn(); //(3)
    
    verify(infoService).getInfo(anyLong());
  }
  
  }

실제 내가 테스트 했던 코드이다. controller에 대한 테스트를 진행하는 것이므로 실제 service가 작동할 필요는 없기 때문에 (1)과 같이 가짜 객체를 사용한다.
(3)과 같이 api를 호출했을때 실제 controller에서 InfoService가 호출되면 가짜 객체를 이용해서 (2)와 같이 내가 return값을 임의로 설정할 수 있다.
이렇게 테스트코드를 먼저 작성한 후 개발을 진행하는게 TDD(테스트주도개발)이라고 한다.
주로 java에서는 테스트 라이브러리로 junit을 대부분 사용했는데, 요즘엔 junit이 아니라 spock으로 많이 대체하는 것 같다.

실제 코드를 짜보면서 느낀점은, 실무에서 사용되는 애플리케이션의 코드와 환경은 복잡하므로 단순하지 않았고 상당한 삽질이 필요했다. security, interceptor 설정 등 차이가 많이 나기때문에 인터넷에서 단순 예문으로는 해결되지 않는 경우들도 많았다. 결국 삽질을 통해서 많이 알아봐야한다. 나중에 테스트 코드 짜면서 어려웠던 점들은 정리해야할 필요가 있을 것 같다..

통합테스트

여러 컴포넌트들이 함께 잘 작동하는지 확인하는 테스트로, 시스템의 전체 흐름을 테스트한다. 이는 데이터베이스, 외부서비스, 파일 시스템 등과 같이 외부 리소스와 상호작용이 잘 되고 있는지 전체적으로 테스트하는 것이다.

  • 키워드 : @SpringbootTest, Postman, Testcontainers

springboot에서는 @springbootTest 어노테이션을 제공하고 있다. 실제 springboot의 모든 빈을 등록하고 데이터베이스를 연결하여 실제 환경과 똑같이 테스트 할 수 있다.
또한 postman 이라는 프로그램을 이용해서 api를 요청하여 이러한 흐름을 쉽게 테스트 하는 방법도 있다. 나는 jwt토큰을 개발하면서 실제 jwt토큰이 잘 작동하고 있는지 테스트 해야했었는데, 이때 postman을 이용했다.

⌨️postman 사용 예시

1) 전역적으로 사용할 변수 설정

2) api 요청을 통해 받아온 response를 환경 변수에 세팅

3) 다른 api 요청시 헤더에 해당 변수 세팅

개발자가 @springbootTest처럼 코드를 이용해서 검증하는 방법도 있지만 postman을 통해서 빠르고 직관적으로 테스트를 진행할 수도 있다.
그리고 최근에 java에서는 Testcontainers라는 통합테스트를 사용한다고 한다. local에서도 도커를 이용해서 통합테스트를 진행 할 수 있는 듯한데 사용해보질 않아서 기회가 된다면 해보도록 하자..

성능 테스트

성능 테스트는 단위, 통합테스트와 다른 유형의 테스트라기 보다는 통합테스트의 하위 범주에 포함된다고 한다. 시스템의 성능 및 안전성을 평가하기 위해 사용되며, 응답시간, 처리량, 자원사용률 등을 측정하여 시스템이 특정 부하 또는 사용 패턴 아래에서 어떻게 동작하는지 평가한다. 대용량 트래픽 발생 시 특정 구간에서 부하가 걸렸다 라는 글들을 많이 봤는데, 이러한 상황들을 개발자가 도구를 통해 임의로 만들어서 예방할 수 있도록 한다.

  • 키워드 : K6, Jmeter

k6 + grafana는 추후에 정리 예정이라 짧게 대쉬보드 이미지만 가져왔다. 보통 k6 + influxDB + grafana 3가지를 사용한다. k6를 통해 임의의 유저들을 생성하고 여러 조건을 만들어 api를 요청한다. 그에 따른 성능에 관한 결과 데이터들을 db에 저장한뒤, grafana를 이용하여 시각화 해준다.


[출처목록]
https://k6.io/docs/results-output/grafana-dashboards/
https://docs.spring.io/spring-framework/reference/testing/spring-mvc-test-framework.html

profile
개발 그렇게 하는거 아닌데의 그렇게를 맡고있습니다

0개의 댓글