2017-09-14 83 views
0

所以我有两个Spring引导项目。在项目A中,我通过服务类调用项目B的控制器来检索包含字符串列表的ResponseEntity。项目A的服务类是消费者,B是在条约用语的提供者:约定:没有找到响应类型的HttpMessageConverter

BookServiceInterfaceImpl.java

@Service("bookService") 
public class BookServiceInterfaceImpl implements BookServiceInterface { 

public ResponseEntity<List<String>> getBookTitlesForCourse(final String courseId){ 
    RestTemplate restTemplate = new RestTemplate(); 
    ResponseEntity<String[]> response = restTemplate.getForEntity("http://localhost:8888/api/book/course/" + courseId, String[].class); 
    List<String> titles = Arrays.asList(response.getBody()); 
    return new ResponseEntity<List<String>>(titles, HttpStatus.OK); 
} 
} 

BookController.java

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

private BookService bookService; 

@Autowired 
public BookController(BookService bookService) { 
    this.bookService = bookService; 
} 

@RequestMapping(method = RequestMethod.GET, value="/book/course/{id}") 
public ResponseEntity<String[]>getBookTitlesForCourse(@PathVariable("id") final long id) { 
    List<Book> books = bookService.findAllBooks(); 
    if(books.isEmpty()) { 
     return new ResponseEntity<>(HttpStatus.NO_CONTENT); 
    } 
    String[] bookTitles = books.stream() 
      .filter(book -> book.getCourseId() == id) 
      .map(book -> book.getTitle()) 
      .toArray(String[]::new); 
    return new ResponseEntity<String[]>(bookTitles, HttpStatus.OK); 
} 
} 

我试图使用约定在两者之间建立合约。因此,到目前为止,我有在消费下面的测试:

BookServiceTest.java

@RunWith(SpringRunner.class) 
@SpringBootTest 
public class BookServiceTest { 

@Rule 
public PactProviderRuleMk2 mockProvider = new PactProviderRuleMk2("test_provider", "localhost", 8080, this); 

@Pact(provider="test_provider", consumer="test_consumer") 
public RequestResponsePact createPact(PactDslWithProvider builder) { 
    return builder 
      .given("test state") 
      .uponReceiving("BookServiceTest test interaction") 
       .path("/api/book/course/1") 
       .method("GET") 
      .willRespondWith() 
       .status(200) 
       .body("{[\"Dont make me think\",\"Clean Code\"]}") 
      .toPact(); 
} 

@Test 
@PactVerification("test_provider") 
public void test_retrieveBooksForcourse_validCourseId_success() { 
    //given 
    final String courseId = "1"; 
    BookServiceInterfaceImpl bookService = new BookServiceInterfaceImpl(); 
    //when 
    ResponseEntity<List<String>> response = bookService.getBookTitlesForCourse(courseId); 
    //then: 
    assertThat(response.getStatusCode(), is(200)); 
    assertThat(response.getBody().size(), is(2)); 
} 
} 

而对于消费者的POM文件是:

的pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
<modelVersion>4.0.0</modelVersion> 

<groupId>com.ocr</groupId> 
<artifactId>new-consumer</artifactId> 
<version>0.0.1-SNAPSHOT</version> 
<packaging>jar</packaging> 

<name>new-consumer</name> 
<description>Demo project for Spring Boot</description> 

<parent> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-parent</artifactId> 
    <version>1.5.6.RELEASE</version> 
    <relativePath /> 
</parent> 

<properties> 
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> 
    <java.version>1.8</java.version> 
</properties> 

<dependencies> 
    <dependency> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter-actuator</artifactId> 
    </dependency> 
    <dependency> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter-web</artifactId> 
    </dependency> 
    <dependency> 
     <groupId>au.com.dius</groupId> 
     <artifactId>pact-jvm-consumer-junit_2.11</artifactId> 
     <version>3.5.5</version> 
     <scope>test</scope> 
    </dependency> 
    <dependency> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-devtools</artifactId> 
     <scope>runtime</scope> 
    </dependency> 
    <dependency> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter-test</artifactId> 
     <scope>test</scope> 
    </dependency> 
</dependencies> 

<build> 
    <plugins> 
     <plugin> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-maven-plugin</artifactId> 
     </plugin> 
    </plugins> 
</build> 

当我运行它,我得到如下:

java.lang.AssertionError: Pact Test function failed with an exception: Could not extract response: no suitable HttpMessageConverter found for response type [class [Ljava.lang.String;] and content type [application/octet-stream] 
at au.com.dius.pact.consumer.BaseProviderRule.validateResult(BaseProviderRule.java:164) 
at au.com.dius.pact.consumer.BaseProviderRule$1.evaluate(BaseProviderRule.java:77) 
at org.junit.rules.RunRules.evaluate(RunRules.java:20) 
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:252) 
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) 
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:191) 
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: org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class [Ljava.lang.String;] and content type [application/octet-stream] 
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:110) 
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:917) 
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:901) 
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:655) 
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613) 
at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:312) 
at com.ocr.newconsumer.service.BookServiceInterfaceImpl.getBookTitlesForCourse(BookServiceInterfaceImpl.java:29) 
at com.ocr.newconsumer.controller.BookServiceTest.test_retrieveBooksForcourse_validCourseId_success(BookServiceTest.java:60) 
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.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) 
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) 
at au.com.dius.pact.consumer.BaseProviderRule.lambda$runPactTest$1(BaseProviderRule.java:150) 
at au.com.dius.pact.consumer.BaseMockServer.runAndWritePact(MockHttpServer.kt:152) 
at au.com.dius.pact.consumer.ConsumerPactRunnerKt.runConsumerTest(ConsumerPactRunner.kt:13) 
at au.com.dius.pact.consumer.BaseProviderRule.runPactTest(BaseProviderRule.java:148) 
at au.com.dius.pact.consumer.BaseProviderRule.access$100(BaseProviderRule.java:21) 
at au.com.dius.pact.consumer.BaseProviderRule$1.evaluate(BaseProviderRule.java:76) 
... 20 more 
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 au.com.dius.pact.consumer.BaseProviderRule.lambda$runPactTest$1(BaseProviderRule.java:150) 
at au.com.dius.pact.consumer.BaseMockServer.runAndWritePact(MockHttpServer.kt:152) 
at au.com.dius.pact.consumer.ConsumerPactRunnerKt.runConsumerTest(ConsumerPactRunner.kt:13) 
at au.com.dius.pact.consumer.BaseProviderRule.runPactTest(BaseProviderRule.java:148) 
at au.com.dius.pact.consumer.BaseProviderRule.access$100(BaseProviderRule.java:21) 
at au.com.dius.pact.consumer.BaseProviderRule$1.evaluate(BaseProviderRule.java:76) 
... 20 more 

所以我不完全的问题是什么,从我知道我敢肯定,这种转换应该不会有大的事情并且应该由Spring处理。有没有我不正确地处理REST调用或测试(第一次使用Pact)?我是否错过了我认为Spring Boot父级/依赖项会有的pom依赖项?

回答

0

对于我们的消费者测试我们扩展ConsumerPactTestMk2。您必须覆盖的其中一种方法是runTest(MockServer ms)runTest方法中的MockServer具有您需要使用的URL的主机部分。因此,您需要更改实现类中的URL以使用扩充的URL。

public class BookServiceInterfaceImpl implements BookServiceInterface { 
    private String hostUrl = "http://localhost:8888"; 
    //provider setter for this variable. 

有了这个功能,您可以使用hostUrl来创建最终的网址。

ResponseEntity<String[]> response = restTemplate.getForEntity(hostUrl + "/api/book/course/" + courseId, String[].class); 

然后在runTest方法中。编辑:Here is an exmaple

+0

所以,我认为你说我应该改变我的实现代码以适应测试库,当不应该在测试库做的工作在这里不管?我会尝试这个方法不管,只是好奇,因为我看不到任何围绕github上的示例使用作为参考覆盖runTest:https://github.com/DiUS/pact-jvm/blob/master/pact-jvm-consumer-junit/src/test/java/au/com/ dius/pact/consumer/examples/ArticlesTest.java – jbailie1991

+0

好的,我已经实现了这个改变,并且改变了测试,以类似于发布的示例。我仍然得到相同的HttpMessageConverter错误,所以不要认为这是问题 – jbailie1991

+0

啊好点。我之前看到过这个错误,并总是找到解决办法。你见过这个吗? https://stackoverflow.com/a/21857557/1490322 –

相关问题