늘상 같은일의 반복이다.
지루하면서도 행복한 일상의 반복이다.

반복적인 학습에 지치기도 하지만
새로운 지식습득의 즐거움이 너무크기때문에
오늘도 열심히 공부해보려한다.


어제는 Test라는 개념과
Spring Boot의 Default 프레워크인 JUnit에 대해서도
간단히 사용하는 클래스와 어노테이션등을 알아보았다.

오늘은 웹애플리케이션 계층별로 테스트하는
슬라이스 테스트에대해 알아볼 예정이다.

Controller 계층 테스트

Controller 계층을 테스트하기위해서는
기본적으로 Postman으로 핸들러 매서드를 호출하여
JSON 객체를 주고 응답받는 방식을 사용했었다.

하지만 이모든 것도 자동화시키고 더욱 프로그래머답게 테스트하기위해선
테스트 코드로 Controller 계층을 테스트해볼 필요가 있다.

MockMvc

@AutoConfigureMockMvc 어노테이션은 Controller 테스트를 위한 애플리케이션의
자동 구성 작업을 해준다. 이중 우리는 MockMvc 같은 클래스의 기능을 사용할 것이다.

@SpringBootTest    
@AutoConfigureMockMvc  
public class ControllerTest {
    @Autowired
    private MockMvc mockMvc;
    
    @Test
    public void postTest() {
        ...
    }
}

테스트 파일의 @SpringBootTest 어노테이션 붙여
Application Context를 생성하고
MockMvc클래스를 사용하기 위한 어노테이션 @AutoConfigureMockMvc를
붙여준 다음 @Autowired로 의존성 주입을 시켜주면 된다.

그렇게 되면 .perfrom(); 이라는 메서드를 사용하여
POST, GET, DELETE, PATCH 등
핸들러 메서드들을 자유롭게 이용할 수 있게 되어진다.

ResultActions actions =
        mockMvc.perform(                       
            post("/api/coffees") 
                .accept(MediaType.APPLICATION_JSON) 
                .contentType(MediaType.APPLICATION_JSON) 
                .content(content) 
        );

간단한 코드 예제를 살펴보자 perform을 통해
uri와 핸들러 메서드 방식 설정을해주고
응답받을 객체 타입 .accept();
전송할 컨텐츠 타입 .contentType();
전송할 컨텐츠 .content();
를 호출하여 각각의 내용들을 담아주면 Controller에서 작성한
api가 호출되게 되어진다.

여기서 반환된 객체는 ResultActions이라는 타입으로 반환되면
후에 검증하는 용도로 사용되어진다.

핸들러 메서드(post(),get(),patech())를 사용하기 위해서는

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;

MockMvcRequestBuliders를 import해야 사용이 가능하다.


Json 객체 받기

여기서 우리는 JSON 객체를 주고받는 것으로 설정했고
Json 객체를 만들기 위해 Google Json 라이브러리를 사용했다.

implementation 'com.google.code.gson:gson:2.8.7'

사용법은 간단하다.

@Autowired
private Gson gson;

필드의 Gson 객체를 주입받도록 설정 후

CoffeeDto.Post post = new Coffee.Post(
        "아메리카노",
        "Americano",
        4500
);
String content = gson.toJson(post);

우리가 Dto 용도로 만들었던 클래스의
해당 타입의 맞는 객체를 gson.toJson(); 안에 넣어주면
String 타입으로 반환되게 되어진다.

그렇게 반환된 객체로 .content();안에 담에주게 되면 끝이다.


MvcResult

위에서 언급했던 ResultAction 타입의 객체로
여러가지 검증 메서드들을 사용할 수 있다.

MvcResult result = actions
        .andExpect(status().isCreated())
        .andExpect(jsonPath("$.data.korName").value(post.getKorName()))
        .andExpect(jsonPath("$.data.engName").value(post.getEngName()))
        .andExpect(jsonPath("$.data.price").value(post.getPrice()))
        .andReturn();

.andExpect(); 메서드로 검증을 할 수 있다.
actions객체는 ResultAction 타입이며

status().isCreated() -> 응답 상태에 대한 검증 (OK,NOT FOUND 등등..)
jsonPath().value() -> 응답받은 Json 객체의 데이터를 검증

추가로 .andReturn(); 메서드를 사용하게되면
MvcResult 클래스 타입으로 반환되는데
해당 클래스의 메서드로 Json 객체를 문자열로 출력하는 것도 가능하다.

System.out.println(result.getResponse().getContentAsString());

위와 같이 getResponse().getContentAsString(); 메서드를
이용하여 실제 어떻게 응답받았는지 출력해볼 수 있다


Service 계층 테스트

데이터 엑세스 계층을 테스트하기 위해서는
한 가지 규칙이있다.

DB의 상태를 테스트 케이스 실행 이전으로 되돌려 놓는다.
라는 규칙이 있다.

이유는 말하지 않아도 알 수 있다.
테스트케이스 실행을하는 데이터를 남겨둘 이유가 없기 때문이다.

가장 원초적인 방법으로는
@BeforeEach - 테스트 레코드 생성 , @AfterEach - 테스트 레코드 삭제
정도 생각해볼 수 있을 것 같다. 하지만 데이터 생성 후
로직에서 예외가 발생하거나하면 데이터가 잔존하는 문제가 생길 수도 있다.

@Transactional 애노테이션을 테스트 클래스에
붙여놓고 Test를 진행하면, 테스트 완료후 rollback();이
되어지기 때문에 편리하게 테스트를 할 수 있다.

@DataJpaTest

Spring에서 데이터 엑세스 계층을 테스트 하기 위해
만들어둔 어노테이션이다.

해당 어노테이션을 추가함으로써, Jpa 기술을 사용하는
Repository의 기능을 정상적으로 사용하기 위한
Configuration을 Spring이 자동으로 해주게 된다.
그리고 해당 어노테이션은 @Transactional을 포함하고 있기에
위에서 설명했던 rollback 처리까지 되어진다.

@DataJpaTest
public class CoffeeRepositoryTest {
    @Autowired
    private CoffeeRepository coffeeRepository;

    @Test
    public void test1(){
        ...
    }
    
    @Test
    public void test2(){
        ...
    }
}

사용 방법은 Controller보다 간단하다.
JPA를 상속받는 Repository를 의존성 주입시킨 객체를 이용하고

@DataJpaTest를 클래스레벨에 붙여주면
트랜잭션이 보장된 Service 계층 테스트가 가능한
Test 클래스가 만들어 진다.



오늘은 Controller 계층을 테스트 하기위한
여러가지 API들을 알아보았다.
확실히 Postman으로 테스트할때는 눈으로 보이지만
프로그램으로 테스트할때 예외발생이라든지, 오류발생이 생기면
한눈에 문제파악하는게 쉽지는 않은 것 같고
연습이 필요할 것 같다.

오늘 공부도 여기서 끝 !


오늘의 커피량: ☕️ ☕️ ☕️
오늘의 점심: 김치찌개, 밥