简体   繁体   中英

Using TestRestTemplate for Spring Integration Testing

I am learning Spring Integration testing and using org.springframework.boot.test.web.client.TestRestTemplate . My Spring Boot version is 2.0.2 and with some default configuration.

My Test class is :

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
public class UserControllerIntegrationTest {

    @Autowired
    TestRestTemplate restTemplate;      

    String userBaseUrl = "/api/user/";

    UserDto userDto;

    @Before
    public void setUp() {

        EnhancedRandom er = EnhancedRandomBuilder.aNewEnhancedRandomBuilder().collectionSizeRange(1, 1).build();

        userDto = er.nextObject(UserDto.class);     

    }

    @Test
    public void registerUser() throws Exception{

        ResponseEntity<ServiceResponse> responseEntity = restTemplate.postForEntity(userBaseUrl+"register_user", userDto, ServiceResponse.class);
        assertEquals(responseEntity.getStatusCode(), HttpStatus.OK);
    }
    }

And controller endpoint method is :

@RequestMapping(value="register_user",method = RequestMethod.POST)  
    public ResponseEntity<ServiceResponse> registerUser(@RequestHeader HttpHeaders headers, @RequestBody UserDto userDto) {

        log.info("Register user");

        try {           
            ServiceResponse serviceResponse = new ServiceResponse("Users listed successfully"); 

            serviceResponse.setData(userService.registerUser(userDto));

            return new ResponseEntity<ServiceResponse>(serviceResponse,HttpStatus.OK);

        } catch (Exception e) {
            GeneralUtil.logError(log, "Error Occurred listing users", e);
            HttpHeaders httpHeaders = ServiceResponse.generateRuntimeErrors(e);
            return new ResponseEntity<>(httpHeaders, HttpStatus.EXPECTATION_FAILED);
        }
    }

And ServiceResponse is :

public class ServiceResponse {

    private Boolean success;
    private String message;
    private Map<String, Object> params;
    private List<?> list;
    private Object data;
//getters,setters.
    }

This API endpoint works well when we test manually but doesn't work while running tests.It gives this error :

org.springframework.web.client.RestClientException: Error while extracting response for type [class com.eeposit.lattice.util.ServiceResponse] and content type [application/json;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.eeposit.lattice.util.ServiceResponse` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.eeposit.lattice.util.ServiceResponse` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (PushbackInputStream); line: 1, column: 2]
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:115)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:991)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:974)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:725)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:680)
    at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:466)
    at org.springframework.boot.test.web.client.TestRestTemplate.postForEntity(TestRestTemplate.java:502)
    at com.eeposit.lattice.controller.UserControllerIntegrationTest.registerUser(UserControllerIntegrationTest.java:61)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
    at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:539)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:761)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:461)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:207)
Caused by: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.eeposit.lattice.util.ServiceResponse` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.eeposit.lattice.util.ServiceResponse` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (PushbackInputStream); line: 1, column: 2]
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:241)
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:223)
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:100)
    ... 39 more
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.eeposit.lattice.util.ServiceResponse` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (PushbackInputStream); line: 1, column: 2]
    at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)
    at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1342)
    at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1031)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1290)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3072)
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:235)
    ... 41 more

I tried to solve this issue googling but cannot fix the issue.

Your problem could be caused by that you get some error response which can't be parsed as ServiceResponse. Try to change the ResponseEntity type to String instead of the ServiceResponse type.

ResponseEntity<String> responseEntity = restTemplate.postForEntity(userBaseUrl+"register_user", userDto, String.class);
System.out.println("This is the response as a String" + responseEntity.getBody());

I believe that way you will be able to see what the call returns.

I solved this problem. I did some modification in the code. I added this :

public HttpHeaders setHeaders(String accesstoken) {

        List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>();
        acceptableMediaTypes.add(MediaType.APPLICATION_JSON);

        HttpHeaders headers = new HttpHeaders();  
        headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setAccept(acceptableMediaTypes);
        headers.set("accesstoken", accesstoken);
        return headers;

    }

And changed the test method to this :

@Test
    public void registerUser() throws Exception{

        super.getLog().info("Register user integration test.");

        HttpHeaders headers = setHeaders(null);
        HttpEntity<UserDto> entity = new HttpEntity<UserDto>(userDto,headers);

        ResponseEntity<String> responseEntity = restTemplate.exchange(userBaseUrl+"register_user", HttpMethod.POST, entity, String.class);  

        assertEquals(responseEntity.getStatusCode(), HttpStatus.OK);
        assertNotNull(responseEntity.getBody());    

        ServiceResponse serviceResponse = super.gson.fromJson(responseEntity.getBody(), ServiceResponse.class);     

        Map<String, Object> data = (Map<String, Object>) serviceResponse.getData();

        assertTrue(data.containsKey("accesstoken"));

        assertTrue(data.containsKey("user"));
    }

Instead of using this :

ResponseEntity<ServiceResponse> responseEntity = restTemplate.postForEntity(userBaseUrl+"register_user", userDto, ServiceResponse.class);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM