pact-foundation / pact-jvm

JVM version of Pact. Enables consumer driven contract testing, providing a mock service and DSL for the consumer project, and interaction playback and verification for the service provider project.
https://docs.pact.io
Apache License 2.0
1.08k stars 479 forks source link

Adding headers when using MockMvcTarget #1339

Open Amarnath9806 opened 3 years ago

Amarnath9806 commented 3 years ago

I am getting below error while passing headers in @TargetRequestFilter public void requestFilter(MockHttpServletRequestBuilder request) { request.header("Content-Type", MediaType.APPLICATION_JSON_VALUE); } java.lang.Exception: Method requestFilter should take only a single HttpRequest parameter

at au.com.dius.pact.provider.junit.InteractionRunner.validateTargetRequestFilters(InteractionRunner.kt:102)
at au.com.dius.pact.provider.junit.InteractionRunner.validate(InteractionRunner.kt:89)
at au.com.dius.pact.provider.junit.InteractionRunner.<init>(InteractionRunner.kt:60)
at au.com.dius.pact.provider.spring.SpringInteractionRunner.<init>(SpringInteractionRunner.kt:77)
at au.com.dius.pact.provider.spring.SpringRestPactRunner.newInteractionRunner(SpringRestPactRunner.kt:52)
at au.com.dius.pact.provider.junit.PactRunner.setupInteractionRunners(PactRunner.kt:116)
at au.com.dius.pact.provider.junit.PactRunner.<init>(PactRunner.kt:110)
at au.com.dius.pact.provider.junit.RestPactRunner.<init>(RestPactRunner.kt:8)
at au.com.dius.pact.provider.spring.SpringRestPactRunner.<init>(SpringRestPactRunner.kt:23)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:104)
at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:86)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:33)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:49)

is there any other method to pass headers in provider tests? Using dependencies : au.com.dius:pact-jvm-provider-spring:4.0.10" au.com.dius:pact-jvm-provider-junit:4.010

Amarnath9806 commented 3 years ago

Complete Provider test

@RunWith(SpringRestPactRunner.class) @Provider("provider-name") @PactFolder("pacts") @SpringBootTest(webEnvironment = RANDOM_PORT) public class PactVerificationTest {

@TargetRequestFilter public void requestFilter(HttpRequest request) { request.addHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE); } @TestTarget public Target target = new SpringBootHttpTarget();

@State({"person"})
public void getDetails() throws Exception{
    target.setRunTimes(1);
    // ... mockito mocks
}

}

uglyog commented 3 years ago

MockHttpServletRequestBuilder is for when you are using MockMvcTestTarget which uses Spring MockMVC to run the test.

For SpringBootHttpTarget, you need to use a normal HttpRequest object.

Amarnath9806 commented 3 years ago

Hi @uglyog My complete test class,

@RunWith(SpringRestPactRunner.class) @SpringBootTest(webEnvironment = RANDOM_PORT) @Provider("car-provider") @Consumer("car-service") @PactBroker( host = "localhost:8081", port = "8081", scheme = "http") public class ProviderPactTest {

private static final Logger logger = LoggerFactory.getLogger(ProviderPactTest.class);

@BeforeEach void before(PactVerificationContext context) { System.setProperty("pact.verifier.publishResults", "true");

context.setTarget(new HttpTestTarget("localhost", 8080));

}

@State("Car exists") public void testGetCarOne() throws Exception {

logger.info("Verfying tests");

}

@TestTemplate @ExtendWith(PactVerificationInvocationContextProvider.class) void pactVerificationTestTemplate(PactVerificationContext context) { context.verifyInteraction(); }

This test works fine when executed as a junit but it is throwing below error while executing with gradlew command org.junit.runners.model.InitializationError at au.com.dius.pact.provider.junit.InteractionRunner.validate(InteractionRunner.kt:93) at au.com.dius.pact.provider.junit.InteractionRunner.(InteractionRunner.kt:62) at au.com.dius.pact.provider.spring.SpringInteractionRunner.(SpringInteractionRunner.kt:77) at au.com.dius.pact.provider.spring.SpringRestPactRunner.newInteractionRunner(SpringRestPactRunner.kt:52) at au.com.dius.pact.provider.junit.PactRunner.setupInteractionRunners(PactRunner.kt:123) at au.com.dius.pact.provider.junit.PactRunner.initialize(PactRunner.kt:116) at au.com.dius.pact.provider.junit.PactRunner.getChildren(PactRunner.kt:140) at org.junit.runners.ParentRunner.getFilteredChildren(ParentRunner.java:426) at org.junit.runners.ParentRunner.getDescription(ParentRunner.java:351) at org.junit.runners.ParentRunner.run(ParentRunner.java:359) at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110) at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58) at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38) at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62) at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51) 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:498) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33) at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94) at com.sun.proxy.$Proxy2.processTestClass(Unknown Source) at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:118) 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:498) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182) at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164) at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:412) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)

Using dependencies au.com.dius:pact-jvm-provider-spring:4.0.10, au.com.dius:pact-jvm-provider-junit5:4.0.10 Plz le me know if this issue is with code or with dependencies

uglyog commented 3 years ago

The first thing I can see is you've set Springboot to use a random port, but then telling the Pact target to use port 8080.

Secondly, you need to provide the full stacktrace which will have the cause of the InitializationError