2017-02-13 2 views
0

스프링 부트 REST 컨트롤러에 대해 JUnit 테스트를 실행하는 중 예외가 발생합니다. Postman을 통해 API를 테스트했으며 예상대로 작동합니다. JUnit 테스트에서 내가 무엇을 놓치고 있는지 확실하지 않습니다.스프링 부트의 REST API에 대한 JUnit 테스트에 실패했습니다.

ProductController.java

@RestController 
@RequestMapping("/api") 
public class ProductController { 

    @Inject 
    private ProductRepository productRepository; 

    //URI: http://localhost:8080/api/products/50 
    @RequestMapping(value = "/products/{productId}", method = RequestMethod.GET) 
    public ResponseEntity<?> getProduct(@PathVariable Long productId) { 
     verifyProductExists(productId); 
     Product product = productRepository.findOne(productId); 
     return new ResponseEntity<>(product, HttpStatus.OK); 
    } 

    protected void verifyProductExists(Long productId) throws ResourceNotFoundException { 
     Product product = productRepository.findOne(productId); 
     if (product == null) { 
      throw new ResourceNotFoundException("Product with id " + productId + " not found..."); 
     } 
    } 

} 

ResourceNotFoundException.java

@ResponseStatus(HttpStatus.NOT_FOUND) 
public class ResourceNotFoundException extends RuntimeException { 

    private static final long serialVersionUID = 1L; 

    public ResourceNotFoundException() { 
    } 

    public ResourceNotFoundException(String message) { 
     super(message); 
    } 

    public ResourceNotFoundException(String message, Throwable cause) { 
     super(message, cause); 
    } 

} 

이죠 스루 :

http://localhost:8080/api/products/1 -> Returns 200 with Product data in JSON format 
http://localhost:8080/api/products/999 -> Returns 404 with Exception data in JSON format 

ProductRestClientTest.java

@RunWith(SpringJUnit4ClassRunner.class) 
public class ProductRestClientTest { 

    static final String VALID_PRODUCT_API_URI = "http://localhost:8080/api/products/35"; 
    static final String INVALID_PRODUCTS_API_URI = "http://localhost:8080/api/products/555"; 
    private RestTemplate restTemplate; 

    @Before 
    public void setUp() { 
     restTemplate = new RestTemplate(); 
    } 

    /* 
    Testing Happy Path scenario 
    */ 
    @Test 
    public void testProductFound() { 
     ResponseEntity<?> responseEntity = restTemplate.getForEntity(VALID_PRODUCT_API_URI, Product.class); 
     assert (responseEntity.getStatusCode() == HttpStatus.OK); 
    } 

    /* 
    Testing Error scenario 
    */ 
    @Test(expected = ResourceNotFoundException.class) 
    public void testProductNotFound() { 
     ResponseEntity<?> responseEntity = restTemplate.getForEntity(INVALID_PRODUCTS_API_URI, Product.class); 
     assert (responseEntity.getStatusCode() == HttpStatus.NOT_FOUND); 
    } 

    @After 
    public void tearDown() { 
     restTemplate = null; 
    } 

} 

예외는 점에서는 예외가 있지만 바디와 포함 된 HTTP 메시지 HTTP를 반환하지 않는 것입니다

Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.759 sec <<< FAILURE! - in com.study.spring.boot.rest.ProductRestClientTest 
testProductNotFound(com.study.spring.boot.rest.ProductRestClientTest) Time elapsed: 0.46 sec <<< ERROR! 
java.lang.Exception: Unexpected exception, expected<com.study.spring.boot.rest.ResourceNotFoundException> but was<org.springframework.web.client.HttpClientErrorException> 
    at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91) 
    at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700) 
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653) 
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613) 
    at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:312) 
    at com.study.spring.boot.rest.ProductRestClientTest.testProductNotFound(ProductRestClientTest.java:42) 
+0

당신이 @IntegrationTest와 테스트 클래스에 주석을 시도? –

답변

1

테스트의 문제점은 RestTemplateDefaultResponseErrorHandler 방법 handleError(ClientHttpResponse response)의 404 응답으로 트리거된다는 것입니다. 귀하의 경우에는

가 (404 상태 코드를 반환 -> 클라이언트 오류)가 원인 HttpClientErrorException :

HttpStatus statusCode = getHttpStatusCode(response); 
    switch (statusCode.series()) { 
     case CLIENT_ERROR: 
      throw new HttpClientErrorException(statusCode, response.getStatusText(), 
        response.getHeaders(), getResponseBody(response), getCharset(response)); 

이 적어도 두 가지 솔루션이 있습니다

하나에서 처리 기본 오류 해제가 당신의 테스트, 어쩌면처럼 setUp() 방법 개선 :

restTemplate.setErrorHandler(new DefaultResponseErrorHandler(){ 
     protected boolean hasError(HttpStatus statusCode) { 
      return false; 
     }}); 

을 그리고 (expected = ResourceNotFoundException.class) 절 FR 제거 om 부정적인 테스트. 응답을 얻고 예외를 예상 한 후에 404를 선언하면 함께 작동하지 않습니다.

또는 MockMvc을 사용하십시오. 훨씬 더 정교한 기능을 제공하며 기본값 당 DefaultResponseErrorHandler를 건너 뜁니다.

예를 들어 테스트는 다음과 같이 수 :

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; 

import org.junit.After; 
import org.junit.Before; 
import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.boot.test.context.SpringBootTest; 
import org.springframework.test.context.junit4.SpringRunner; 
import org.springframework.test.web.servlet.MockMvc; 
import org.springframework.test.web.servlet.ResultActions; 
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; 
import org.springframework.web.context.WebApplicationContext; 

@RunWith(SpringRunner.class) 
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) 
public class ProductRestClientTestWithMockMvc { 

    private static final String PRODUCT_API_URI = "http://localhost:8080/api/products/{productId}"; 
    private MockMvc mockMvc = null; 

    @Autowired 
    private WebApplicationContext webApplicationContext; 

    @Before 
    public void before() throws Exception { 
     mockMvc = webAppContextSetup(webApplicationContext).build(); 
    } 

    @After 
    public void after() throws Exception { 
     mockMvc = null; 
    } 

    /* 
    * Testing Happy Path scenario 
    */ 
    @Test 
    public void testProductFound() throws Exception { 
     final MockHttpServletRequestBuilder builder = get(PRODUCT_API_URI, 35); 
     final ResultActions result = mockMvc.perform(builder); 
     result.andExpect(status().isOk()); 
    } 

    /* 
    * Testing Error scenario 
    */ 
    @Test 
    public void testProductNotFound() throws Exception { 
     final MockHttpServletRequestBuilder builder = get(PRODUCT_API_URI, 555); 
     final ResultActions result = mockMvc.perform(builder); 
     result.andExpect(status().isNotFound()); 
    } 

} 
0

JUnit 테스트보다 실행하는 동안 상태 코드. 이 경우에는 404 코드가 있지만 아무도이 코드를 예외로 변환하지 않습니다. 원하는 예외를 얻으려면 restTemplate에게 404가 충족 될 때 ResourceNotFoundException을 던지도록 지시해야합니다. 기본적으로 오류 처리기가 필요합니다.

RestTemplate restclient = new RestTemplate(); restclient.setErrorHandler (new MyResponseErrorHandler());

희망이 있습니다.

+0

'MyResponseErrorHandler'는 내가 생성해야하는 새로운 클래스입니까? – user2325154

+0

예. http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/ResponseErrorHandler.html을 구현해야합니다. – Pirulino