개요

항상 그렇듯 본문에 들어가기전에 왜 테스트 코드 작성에 대한 글을 작성하는지 간략하게 설명하겠다.

2년차로 접어들고 있는 내 개발 경력에서 테스트 코드라는것을 한번도 작성해본적이 없었다.

하지만 여기저기 블로그를 보고 많은 개발을 접하며 테스트 코드의 중요성은 자연스레 알고 있었다.

그래서 이번에 개인적으로 진행하는 사이드 프로젝트의 백엔드에 테스트 코드를 작성해보면 좋을것 같았다.

테스트 해야 하는 RestAPI

이 글에서 예제로 쓸 RestAPI는 바로 회원가입 하는 API를 예제로 사용할것이다.

대부분 Json을 주고 받는 RestAPI 특성상 어떤 API에도 응용 가능하니 신중하게 보면 좋을듯하다.

 

예를 들어 /user/join으로 요청하는 API가 있다.

 

이 API를 요청할때에는 다음과 같은 파라미터 값들을 보내야한다.

{
"username" : "test",
"email" : "test@test.com",
"phone" : "010-0000-0000",
"company" : "testcompany"
}
 

그리고 성공적으로 요청이 실행되었을 시 다음과 같은 값들이 반환된다.

{ "result": "0", "message": "success"}

아주 단순한 RESTAPI의 전형적인 형태이다.

이 단순한 API를 테스트하는 코드를 아주 간단하게 적어보도록 하겠다.

테스트 코드

먼저 import 해야하는 부분들부터 정리하겠다.

import static org.junit.Assert.assertEquals;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.json.JSONObject;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.transaction.annotation.Transactional;

import 같은 부분은 센스있게 처리하면 되는 부분이지만 처음 해보시는 분들을 위해 정리했다.

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
@Transactional
public class LoginControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private UserCryptionService userCryptionService;

    @DisplayName("회원가입 테스트")
    @Test
    public void testJoin() throws Exception {
        // Create a test user
        UserEntity testUser = UserEntity.builder()
                .username("test")
                .email("test@test.com")
                .phone("010-0000-0000")
                .company("testcompany")
                .build();
        String json = objectMapper.writeValueAsString(testUser);

        // Make a request to join with the test user
        MvcResult result = mockMvc.perform(post("/user/join")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(json))
                .andExpect(status().isOk())
                .andReturn();

        // Check the result
        JSONObject response = new JSONObject(result.getResponse().getContentAsString());
        assertEquals("0", response.get("result"));
        assertEquals("success", response.get("message"));
    }

}

클래스 위에 붙은 어노테이션

일단 클래스 위에 붙은 어노테이션들부터 설명을 하겠다.

총 4개의 어노테이션이 붙어 있다.

@RunWith(SpringRunner.class) @SpringBootTest @AutoConfigureMockMvc @Transactional

@RunWith(SpringRunner.class)

이 어노테이션은 테스트 방법을 확장할때 사용되는 어노테이션이다.

위와 같이 SpringRunner.class를 정의하게 되면 JUnit4 프레임워크가 SpringRunner.class라는 내장 Runner를 실행하게 된다.

아직 완벽히 감을 잡진 못하였다. 조금 더 공부가 필요해 보인다.

@SpringBootTest

@SpringBootTest 어노테이션은 스프링부트에서 테스트를 위해 필요한 거의 모든 의존성을 주입해준다.

또한 여러가지 옵션값으로 어떤 환경에서 테스트할지 정할 수 있다.

그에 대한 내용은 다른 글에서 따로 서술하고 일단 이 정도 설명으로 넘어가도록 하겠다.

@AutoConfigureMockMvc

@AutoConfigureMackMvc 어노테이션은 Mock 테스트를 위한 의존성들을 주입해준다.

Mock 테스트에 대해서도 따로 다른 글에서 서술하도록 하겠다.

@Transactional

@Transactional은 클래스나 메서드에 붙여줄 경우, 해당 범위 내 메서드가 트랜잭션이 되도록 보장해준다.. 라고 한다.

그리고 이 코드에서는 테스트로 insert한 테스트값들을 다시 rollback 시키는 용도로 알고 있지만 잘 모르겠다

이 부분도 더 공부가 필요해보인다.

메소드 설명

조금씩 잘라서 코드를 설명하도록 하겠다.

UserEntity testUser = UserEntity.builder()
                .username("testuser")
                .email("testuser@example.com")
                .phone("1234567890")
                .company("testcompany")
                .encUserInfo("gvTzCAKAwc08cwJDYA8JnQ==")
                .build();
String json = objectMapper.writeValueAsString(testUser);

 기존에 사용하고 있던 UserEntity 객체에 맞춰 데이터를 빌드해주고 objectMapper를 이용하여 문자열로 변환시켜준다.

// Make a request to join with the test user
MvcResult result = mockMvc.perform(post("/user/join")
                 .contentType(MediaType.APPLICATION_JSON)
                 .content(json))
         .andExpect(status().isOk())
         .andReturn();

// Check the result
JSONObject response = new JSONObject(result.getResponse().getContentAsString());
assertEquals("0", response.get("result"));
assertEquals("success", response.get("message"));

MockMvc를 이용해서 post로 /user/join api로 위에서 파싱해놨던 json 문자열을 보낸다.

andExpect로 http status가 ok인 범위내로 리턴되는것을 예상한다.

 

Check the result 주석 아래로는 위에 설명했던 성공시 리턴값을 JSONObject 타입으로 받아 예상하고 있던 결과값과 일치하는지 비교

 

성공한다면 넘어가고 일치하지 않으면 오류를 보여준다.

 

이렇게 간단하게 스프링부트에서 RestAPI 테스트 코드 작성을 해보았다.

 

 

반응형
복사했습니다!