在这个例子中,我遇到了编写junit测试的问题,该测试使用了HAL格式的休息服务。据我所知,我可以使用MockRestServiceServer伪造通信。你可以找到here两个简单的弹簧应用程序;一个提供HAL格式的休息服务和一个消费它的服务。当两项服务都启动时,一切正常。
因此,当您使用命令mvn spring-boot:run启动这两项服务并导航到http://localhost:8080/products/list时,您可以看到所使用的休息服务。
使用者自己使用修改后的RestTemplate从类型PagedResources请求响应实体。我的消费者测试定义了一个响应体,它看起来与来自"提供者的正常请求完全相似。服务。
我的测试
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构造函数。那么测试该代码的最佳解决方案是什么?
提前谢谢!
答案 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);
}