I'm running a simple message provider test:
@RunWith(PactRunner.class)
@Provider("userservice")
@PactFolder("../pact-message-consumer/target/pacts")
@SpringBootTest
public class MessageProviderTest {
@TestTarget
public final Target target = new AmqpTarget(Collections.singletonList("io.reflectoring"));
@PactVerifyProvider("a user created message")
public String verifyUserCreatedMessage() {
return "{\"testParam1\": \"value1\",\"testParam2\": \"value2\"}";
}
}
Executing this test results in
Failures:
0) a user created message
No annotated methods were found for interaction 'a user created message'. You need to provide a method annotated with @PactVerifyProvider("a user created message") that returns the message contents.
The cause for this is that the Reflections call in ProviderVerifier#verifyResponseByInvokingProviderMethods doesn't find the @PactVerifyProvider annotation on my test method. There must be something wrong with the setup of the Reflections instance (class loader?).
When I'm using the following code snippet from a test, the annotation is found:
Reflections r = new Reflections(ClasspathHelper.forPackage("io.reflectoring"), new MethodAnnotationsScanner());
Set<Method> methods = r.getMethodsAnnotatedWith(PactVerifyProvider.class);
How are you running the test, from Maven or from your IDE?
From both Gradle and the IDE.
@uglyog
I took a deeper look. In ProviderVerifier#verifyResponseByInvokingProviderMethods() the ConfigurationBuilder used for the Reflections instance is initialized with classpath URLs via def urls = projectClasspath.get().
Running my test from the IDE, the resolved URLs are:
0 = {URL@3601} "file:/C:/Users/Tom/AppData/Local/Temp/classpath1765335879.jar"
1 = {URL@3602} "file:/C:/Users/Tom/.IntelliJIdea2018.2/system/groovyHotSwap/gragent.jar"
2 = {URL@3603} "file:/C:/Users/Tom/.IntelliJIdea2018.2/system/captureAgent/debugger-agent.jar"
None of those JARs contains my classes.
@uglyog did you have a chance to look into this?
I've run a few, and they work for me in IntelliJ. Looks like you are getting an empty classpath, not your project's. Check your run configuration in IntelliJ to see what classpath is being set.
The AmqpTarget is using ClassLoader.getSystemClassLoader() to get the classpath to use. You could try extending a class from AmqpTarget and use the classpath from the test class to see if that works. Just override the setupVerifier method and then override the projectClasspath field on the verifier.
@uglyog I still couldn't get it to work, even when overriding the projectClasspath field. Must be some issue with the classloader.
I can get it to work when overriding the whole usage of Reflections (i.e. subclassing AmqpTarget and ProviderVerifier, but that is a very ugly workaround (see here).
Instead of using a specific classloader, I simply use Reflections r = new Reflections(packages, new MethodAnnotationsScanner()); to scan the classpath for annotations.
Why does ProviderVerifier use a specific class loader? Wouldn't it make sense to use the Reflections default as I did above?
The problem is that different build tools setup the classpaths in different ways. Pact-JVM also supports running verifications from Gradle, Maven, Leiningen and SBT.
However, what we can do is default it to no classpath, and if it hasn't been overridden by one of the build plugins, then use the default.
We run into the same problem. But in combination with pact-jvm-provider-junit5_2.12 and maven.
The PactVerifyProvider-annotation will not be found running with maven.
The same problem with pact-jvm-provider-junit_2.12 version 3.6.1.
AmqpTarget works from IntelliJ but it does not from maven.
@PMT87 @gumartinm You need to set the Maven Surefire plugin to use an isolated class loader. For example:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
</configuration>
</plugin>
@uglyog my test class setup is identical to the one @thombergs has and I am using pact-jvm-provider-junit_2.12 version 3.6.3 along with the suggested useSystemClassLoader configuration on surefire.
When building with Maven I am still getting the same error:
No annotated methods were found for interaction 'test message'. You need to provide a method annotated with @PactVerifyProvider("test message") that returns the message contents
Any idea on what else I can do for this?
@eranberg are you able to provide your POM file?
@uglyog My project is meant to demonstrate how to use Pact with our existing technological stack and libraries so I am using both consumer and provider in the same project to represent the whole lifecycle of the testing environment.
I use NetBeans (or Eclipse) as IDE and Maven for building it all.
The project setup is a bit complicated so I stripped out most of the complication and these are the bare Pact related parts:
<dependencies>
<!-- Contract testing dependencies -->
<dependency>
<groupId>au.com.dius</groupId>
<artifactId>pact-jvm-consumer-junit_2.12</artifactId>
<version>3.6.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>au.com.dius</groupId>
<artifactId>pact-jvm-provider-junit_2.12</artifactId>
<version>3.6.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>au.com.dius</groupId>
<artifactId>pact-jvm-provider-spring_2.12</artifactId>
<version>3.6.3</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
</plugin>
<!-- invoke Pact Contract testing -->
<plugin>
<groupId>au.com.dius</groupId>
<artifactId>pact-jvm-consumer-maven_2.12</artifactId>
<version>3.6.3</version>
</plugin>
<plugin>
<groupId>au.com.dius</groupId>
<artifactId>pact-jvm-provider-maven_2.12</artifactId>
<version>3.6.3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
</configuration>
</plugin>
</plugins>
</build>
@eranberg I was experiencing the same issue but with 3.6.4. I found that after upgrading maven-surefire-plugin, everything started to work:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
</configuration>
</plugin>
Intermediate versions may work, however I didn't look into it.
Thanks @jon-ruckwood I will update the docs to specify that version as a minimum.
@jon-ruckwood @uglyog
I tried:
I still get the same error after all of these upgrades...
Any idea what to do next?
@eranberg have a look at https://github.com/uglyog/pact-maven-amqp-test, it is a simple project that works with Maven 3.5. You'll need to compare it to yours to work out what the issue is.
@uglyog Thanks for providing the github project with the testing samples. It worked out of the box for me.
The example you provided also helped me setup my project in a better way and now I am on to new issues :)
Had this issue as well. My issue is that I am using Java 11. Upgraded to pact-jvm-consumer-junit version 4.0.0-beta.2 and I have provider verification working again.
Closing this as there looks like there are work arounds for all the issues
Most helpful comment
@eranberg I was experiencing the same issue but with
3.6.4. I found that after upgradingmaven-surefire-plugin, everything started to work:Intermediate versions may work, however I didn't look into it.