如何编写JUnit测试以在Spring Boot中使用PagedResources <t>?

时间:2015-07-27 14:36:01

标签: junit spring-boot spring-data-rest

在这个例子中,我遇到了编写junit测试的问题,该测试使用了HAL格式的休息服务。据我所知,我可以使用MockRestServiceServer伪造通信。你可以找到here两个简单的弹簧应用程序;一个提供HAL格式的休息服务和一个消费它的服务。当两项服务都启动时,一切正常。

因此,当您使用命令mvn spring-boot:run启动这两项服务并导航到http://localhost:8080/products/list时,您可以看到所使用的休息服务。

使用者自己使用修改后的RestTemplate从类型PagedResources请求响应实体。我的消费者测试定义了一个响应体,它看起来与来自&#34;提供者的正常请求完全相似。服务。

我的测试

package consumer;

import static org.mockito.Mockito.when;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
import static org.springframework.test.util.AssertionErrors.assertEquals;

import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.client.MockRestServiceServer;
import org.springframework.web.client.RestTemplate;

import consumer.model.Product;
import consumer.service.ProductServiceImpl;
import consumer.service.util.CustomRestTemplate;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ConsumerApplication.class)
@WebAppConfiguration
@IntegrationTest
public class ConsumerApplicationTests {
    private MockRestServiceServer mockServer;
    private RestTemplate restTemplate;

    @Mock
    private CustomRestTemplate customRestTemplate;

    @InjectMocks
    private ProductServiceImpl productServiceImpl;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        this.restTemplate = new RestTemplate();
        this.mockServer = MockRestServiceServer.createServer(this.restTemplate);
        String responseBody = "\"_links\" : {    \"self\" : {      \"href\" : \"http://localhost:1234/products/list\"    }  },  \"_embedded\" : {    \"products\" : [ {      \"name\" : \"Product 1\",      \"price\" : 0.99,      \"_links\" : {        \"self\" : {          \"href\" : \"http://localhost:1234/v1/products/list/product/1\"        }      }    }]  }}";
        this.mockServer.expect(requestTo("http://localhost:1234/products?size=" + Integer.MAX_VALUE)).andExpect(method(HttpMethod.GET))
        .andRespond(withSuccess(responseBody, MediaType.parseMediaTypes("application/hal+json").get(0)));
    }

    @Test
    public void contextLoads() {
        when(customRestTemplate.getRestTemplateJackson2HttpMessageConverter()).thenReturn(restTemplate);

        List<Product> productList = productServiceImpl.retrieveAllProduct();
        assertEquals("Expected one product", 1, productList.size());
        mockServer.verify();
    }

}

当我执行测试时,我收到了错误:

org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Can not instantiate value of type [simple type, class org.springframework.hateoas.PagedResources<consumer.model.Product>] from String value ('_links'); no single-String constructor/factory method
at [Source: java.io.ByteArrayInputStream@1966492; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate value of type [simple type, class org.springframework.hateoas.PagedResources<consumer.model.Product>] from String value ('_links'); no single-String constructor/factory method
at [Source: java.io.ByteArrayInputStream@1966492; line: 1, column: 1]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:208)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:200)
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:97)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:809)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:793)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:572)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:530)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:476)
at consumer.service.ProductServiceImpl.retrieveAllProduct(ProductServiceImpl.java:35)
at consumer.ConsumerApplicationTests.contextLoads(ConsumerApplicationTests.java:58)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
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.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:224)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
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:68)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
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:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not instantiate value of type [simple type, class org.springframework.hateoas.PagedResources<consumer.model.Product>] from String value ('_links'); no single-String constructor/factory method
at [Source: java.io.ByteArrayInputStream@1966492; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:770)
at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:277)
at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:289)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1141)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:135)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:126)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3066)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2221)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:205)
... 39 more

如果我没有完全错误,则会发生错误,因为PagedResources没有String构造函数。那么测试该代码的最佳解决方案是什么?

提前谢谢!

1 个答案:

答案 0 :(得分:1)

检查answer。这对我来说是非常有用的。基本上,你要做的就是从Controller中删除PagedResourcesAssembler参数。并将其构建到方法中。

@RequestMapping(method=RequestMethod.GET)
public ResponseEntity<PagedResources<AccountResource>> getAccounts(
        @RequestParam(value="name", required = false) String name, 
        @RequestParam(value="username", required = false) String username, 
        @RequestParam(value="email", required = false) String email, 
        @RequestParam(value="lastName", required = false) String lastName,
        @RequestParam(value="size", required = true, defaultValue = "10") Integer size,
        @RequestParam(value="page", required = true, defaultValue = "0") int page,
        @RequestParam(value="sort", required = false, defaultValue = "username") String sort,
        @RequestParam(value="direction", required = false, defaultValue = "asc") String direction,
        UriComponentsBuilder uriBuilder,
        HttpServletRequest request, 
        HttpServletResponse response) {

    // Build page request
    AccountList list = null;
    Page<Account> resultPage = null;
    Direction sortDirection = Direction.ASC;
    if(direction.equals("desc")) {
        sortDirection = Direction.DESC;
    }
    PageRequest pReq = new PageRequest(page, size, sortDirection, sort);

    resultPage = accountService.findAll(pReq);

    HateoasPageableHandlerMethodArgumentResolver resolver = new HateoasPageableHandlerMethodArgumentResolver();
    PagedResourcesAssembler<Account> accountPageAssembler = new PagedResourcesAssembler<Account>(resolver, null);
    return new ResponseEntity<PagedResources<AccountResource>>(accountPageAssembler.toResource(resultPage, new AccountResourceAsm()), HttpStatus.OK);
}