Postman에서 Mock Server과 API 만들고 테스트하기 (하)
728x90
반응형

 

 

Postman에서 Mock Server과 API 만들고 테스트하기 (상)

서버 개발자라면 보통 제공하는 입장에서 개발을 할 것이다. 하지만 때로는 제공받는 경우를 고려해서 개발을 해야할 때도 있다. 그런데 만약 스펙만 존재하고 실제 동작하지 않는 API를 염두하

devvkkid.tistory.com

 

이전 포스팅에서는 포스트맨으로 가상 API를 만들어 두었다. 이제 이 API를 스프링에서 다뤄보도록 하겠다. (어우 신난다.) 여기서 필요한 dependencies는 다루지 않는다. 해당 정보가 필요한 분들은 아래 필자의 github 링크를 참고하길 바란다. 또한 앞으로 진행할 실습코드의 전체 구조도 이 링크에 있으니 참고하길 바란다.

 

Postman에서 Mock Server과 API 만들고 테스트하기 · conquerex/WhatTheSpringDataJpa@94995a8

Permalink This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository. Browse files Postman에서 Mock Server과 API 만들고 테스트하기 Loading branch information Showing 7 changed files with 188

github.com

 

 

 

 

 

🏃‍♂️ 모델 생성

필요한 모델부터 생성해보자. 요청과 응답, 각각에 필요한 것이다.

// 요청용
@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    private Long id;

    private String name;

    private int age;
}



// 응답용
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class PersonResponse {
    private String result;
    private String username;
}

 

 

🏃‍♂️ Service 생성

별도의 Repository는 없이 진행되었다. 그래서 Service부터 개발을 진행해본다. "mockserver_url"은 이전 포스팅에서 만든 Mock server의 URL을 copy해서 적용하면 된다.

@Service
@AllArgsConstructor
@Slf4j
public class RestTemplateTestService {

    private final ApiService<PersonResponse> apiService;

    public PersonResponse callPostExternalServer() {
        Person person = Person.builder()
                .age(22)
                .name("John")
                .build();

        HttpHeaders headers = new HttpHeaders();
        PersonResponse response = apiService
                .post("mockserver_url/testapi/first", headers, person, PersonResponse.class)
                .getBody();
        System.out.println(">>>> response = " + response);
        return response;
    }
}

 

 

🏃‍♂️ Controller 생성

앞에서 만든 Service를 호출하는 Controller를 구현해보자. ResponseEntity는 springframework에서 제공되는, HttpEntity를 상속받아 구현된 클래스다.

@RestController
@AllArgsConstructor
@Slf4j
public class RestTemplateTestController {

    private final RestTemplateTestService restTemplateTestService;

    @PostMapping
    public ResponseEntity<PersonResponse> restTemplateTest1() {
        return ResponseEntity.ok(restTemplateTestService.callPostExternalServer());
    }
}

 

HttpEntity는 HttpHeaders와 Body로 구성되어 있다. ResponseEntity는 사용자의 요청에 의한 응답을 HttpEntity의 구조에 맞게 보여주는 역할을 한다. 이 때, 요청은 HttpRequest에서 이루어진다. 그런데 지금까지 HttpRequest를 다룬 부분이 없었다. 이건 RestTemplate에서 해결해준다.

 

 

 

🏃‍♂️ RestTemplate과 Configuration

RESTful하게 API 통신을 하게끔 도와주는 역할을 RestTemplate이 하게된다. 그럼 RestTemplate을 사용하는 부분마다 위에 언급한 HttpRequest를 세팅해줘야할까? 그럴필요없다. 우리에겐 Configuration 어노테이션이 있으니깐. 아래와 같이 구현하면 런타임시 Bean 메서드가 처리된다. RestTemplate이 Bean으로 등록되면 이제 어디서든 RestTemplate을 사용할 때마다 HttpRequest를 생성하는 BufferingClientHttpRequestFactory를 함께 이용할 수 있다.

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
        return restTemplateBuilder
                .requestFactory(() -> new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()))
                .setConnectTimeout(Duration.ofMillis(5000)) // connection-timeout
                .setReadTimeout(Duration.ofMillis(5000)) // read-timeout
                .additionalMessageConverters(new StringHttpMessageConverter(Charset.forName("UTF-8")))
                .build();
    }
}

 

 

 

🏃‍♂️ ApiService 생성

이제 API를 호출하는 클래스를 만들어보자. RestTemplate의 exchage 메서드를 사용해 비교적 편하게 HTTP 메서드를 사용할 수 있다. 여기까지 구현하면 테스트할 준비가 완료된 셈이다.

@Service
@AllArgsConstructor
@Slf4j
public class ApiService<T> {

    private final RestTemplate restTemplate;

    public ResponseEntity<T> post(String url, HttpHeaders httpHeaders, Object body, Class<T> clazz) {
        return callApiEndpoint(url, HttpMethod.POST, httpHeaders, body, clazz);
    }

    private ResponseEntity<T> callApiEndpoint(String url, HttpMethod httpMethod, HttpHeaders httpHeaders, Object body, Class<T> clazz) {
        return restTemplate.exchange(url, httpMethod, new HttpEntity<>(body, httpHeaders), clazz);
    }
}

 

 

 

🏃‍♂️ Mock API를 불러보는 Test

화룡점정. 테스트를 해보자. API에서 정상적으로 호출되는지(getStatusCodeValue), 원하는 값이 들어오는지(getBody().getUsername) 확인해본다.

@SpringBootTest
@Transactional
class RestTemplateTestServiceTest {

    @Autowired
    RestTemplateTestController controller;

    @Test
    public void restTemplateTest() {
        ResponseEntity<PersonResponse> entity = controller.restTemplateTest1();
        System.out.println(">>> entity = " + entity.getStatusCode());
        System.out.println(">>> entity = " + entity.getBody().getResult());
        System.out.println(">>> entity = " + entity.getBody().getUsername());
        Assertions.assertEquals(entity.getStatusCodeValue(), 200);
        Assertions.assertEquals(entity.getBody().getUsername(), "John");
    }
}

 

정상적으로 테스트가 완료되면 아래와 같이 포스트맨에서 응답처리한 Log를 볼 수 있다.

 

 

 

🤯 삽질 공유 : UnknownContentTypeException

테스트 과정에서 다음과 같은 에러로 인해 한참을 고생했었다.

org.springframework.web.client.UnknownContentTypeException:
Could not extract response: no suitable HttpMessageConverter found for response type [class what.the.springdatajpa.resttemplate.model.PersonResponse] and content type [text/html;charset=utf-8]

 

이 상태로 포스트맨에서 API 호출을 해보면 아래처럼 일반 text/html로 응답이 들어온다.

 

😜 해결방법
이는 응답의 Content-Type을 application/json으로 지정하지 않아서 생긴 문제다. Example 응답의 Headers에 Content-Type을 아래와 같이 입력하면 해결된다.

 

 

 

본 코드들은 preamtree님의 블로그를 참고하여 작성되었다. 이 코드에서 RestTemplate 쓰임새에 대해 자세히 알고 싶다면 preamtree님의 블로그를 참고하자.

 

[Spring Boot] RestTemplate 활용 1 - 응답 타입 일반화

 작은 규모의 서비스를 개발한다면 서버와 클라이언트 간 호출이 대부분일 것이다. 하지만 더 큰 서비스가 될 수록 서버와 서버간 HTTP 호출이 필요해진다. 서버 아키택처가 MSA와 같은 형태라면

preamtree.tistory.com

 

 

 

 

조금 헷갈릴 수 있어도 천천히 하면 할 수 있다. 나도 했으니. 모두들 화이팅!!!

 

 

 

728x90
반응형