So habe ich zwei Spring-Boot-Projekte. In Projekt A rufe ich über eine Serviceklasse den Controller von B an, um eine ResponseEntity mit einer Liste von Strings zu erhalten. Projekt A Service-Klasse ist der Verbraucher und B ist der Anbieter in Pact Terminologie:Pakt: kein HttpMessageConverter für Antworttyp gefunden
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);
}
}
Ich versuche zu verwenden Pakt, um einen Vertrag zwischen den beiden zu erstellen. So weit ich den folgenden Test in den Verbraucher:
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));
}
}
Und die pom-Datei für den Verbraucher:
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>
Als ich dies ausführen, bekomme ich die folgende: Was
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
So bin ich nicht genau das Problem ist, von dem, was ich weiß, ich bin ziemlich sicher, diese Art der Umwandlung sollte keine große Sache und sollte von Spring behandelt werden. Gibt es etwas, was ich in Bezug auf den REST-Aufruf oder den Test falsch mache (zum ersten Mal mit Pact)? Fehle ich eine Abhängigkeit in der Pom, dass ich die Spring Boot Eltern/Abhängigkeiten angenommen hätte?
Also ich denke du sagst, ich sollte meinen Implementierungscode ändern, um zu einer Testbibliothek zu passen, wann sollte nicht die Testbibliothek die Arbeit hier unabhängig machen? Ich werde diesen Ansatz trotzdem versuchen, nur neugierig wie ich nicht sehen kann alles über ridTest im Beispiel auf github im als Referenz verwenden: https://github.com/DiUS/pact-jvm/blob/master/pact-jvm-consumer-junit/src/test/java/au/com/ dius/pact/consumer/examples/ArticlesTest.java – jbailie1991
Ok, ich habe die Änderung implementiert und den Test geändert, um dem veröffentlichten Beispiel zu ähneln. Ich bekomme immer noch den gleichen HttpMessageConverter-Fehler, also glaube nicht, dass das das Problem ist – jbailie1991
Ah guter Punkt. Ich habe diesen Fehler schon einmal gesehen und immer einen Weg gefunden. Hast du das gesehen? https://stackoverflow.com/a/21857557/1490322 –