I am testing to create a Async Pact for a test application, that uses RabbitMQ I got the application running but the test to create the pact fails with the following error.
%TESTS 3,verifyCreatePersonPact(io.reflectoring.MessageConsumerTest)
%ERROR 3,verifyCreatePersonPact(io.reflectoring.MessageConsumerTest)
%TRACES
java.lang.NullPointerException: Cannot read the array length because "bytes" is null
at java.base/java.lang.String.<init>(String.java:1437)
at io.reflectoring.MessageConsumerTest.verifyCreatePersonPact(MessageConsumerTest.java:45)
Here is the gradle file:
plugins {
id 'org.springframework.boot' version '3.1.0'
id 'io.spring.dependency-management' version '1.1.0'
id 'java'
id 'au.com.dius.pact' version '4.6.1'
id 'java-library'
}
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-amqp'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'com.h2database:h2:1.4.196'
compileOnly 'org.projectlombok:lombok:1.18.2'
runtimeOnly 'javax.xml.bind:jaxb-api:2.3.1'
runtimeOnly 'org.javassist:javassist:3.23.1-GA'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'au.com.dius.pact.consumer:junit5:4.6.1'
}
test {
useJUnitPlatform()
}
bootRun {
jvmArgs = ["-Xdebug", "-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"]
}
And here is the Test file
package io.reflectoring;
import java.io.IOException;
import au.com.dius.pact.consumer.MessagePactBuilder;
import au.com.dius.pact.consumer.dsl.PactDslJsonBody;
import au.com.dius.pact.consumer.junit5.PactConsumerTestExt;
import au.com.dius.pact.consumer.junit5.PactTestFor;
import au.com.dius.pact.consumer.junit5.ProviderType;
import au.com.dius.pact.core.model.annotations.Pact;
import au.com.dius.pact.core.model.messaging.MessagePact;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
@ExtendWith(PactConsumerTestExt.class)
public class MessageConsumerTest {
private byte[] currentMessage;
@Autowired
private MessageConsumer messageConsumer;
@Pact(provider = "userservice", consumer = "userclient")
public MessagePact userCreatedMessagePact(MessagePactBuilder builder){
PactDslJsonBody body = new PactDslJsonBody();
body.stringType("messageUuid");
body.object("user")
.numberType("id", 42L)
.stringType("name", "Zaphod Beeblebrox")
.closeObject();
// @formatter:off
return builder
.expectsToReceive("a user created message")
.withContent(body)
.toPact();
// @formatter:on
}
@Test
@PactTestFor(pactMethod = "userCreatedMessagePact", providerType = ProviderType.ASYNCH)
void verifyCreatePersonPact() throws IOException {
messageConsumer.consumeStringMessage(new String(this.currentMessage));
}
/**
* This method is called by the Pact framework.
*/
public void setMessage(byte[] message) {
this.currentMessage = message;
}
}
I am following this example: https://github.com/thombergs/code-examples/blob/master/pact/pact-message-consumer/src/test/java/io/reflectoring/MessageConsumerTest.java
But I am updating the java version, gradle and also the pact version.
Thanks for your help.
So I already tried adding @BeforeEach to the setMessage method. And crafting the message there too.
If someone could give me a hint on what could be failing? Also if it works with a later version of gradle it would be great.
I don't think setMessage
is a thing, or at least it's not anymore.
An example project using a relatively recent version can be found here: https://github.com/pactflow/example-consumer-java-kafka/blob/master/src/test/java/io/pactflow/example/kafka/ProductsPactTest.java#L49
@Test
@PactTestFor(pactMethod = "createPact")
void test(List<Message> messages) throws Exception {
ObjectMapper mapper = new ObjectMapper();
System.out.println("Message received -> " + messages.get(0).contentsAsString());
Product product = mapper.readValue(messages.get(0).contentsAsString(), Product.class);
assertDoesNotThrow(() -> {
listener.listen(product);
});
}
Note how the message is injected directly into the test.