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

Exception when no pacts to verify & test template has also an `HttpRequest` parameter #1564

Open fragonib opened 2 years ago

fragonib commented 2 years ago

When there is no PACTs to verify (that satisfy the constraints) PactVerificationContext context is null. The prefered solution is to check that. But if TestTemplate method has also an HttpRequest parameter like:

    @TestTemplate
    @ExtendWith(PactVerificationSpringProvider.class)
    void pactVerificationTestTemplate(PactVerificationContext context, HttpRequest request) throws ProtocolException {
        if (context != null) { // Can be null when there are no PACT defined on Broker
            removeContextFromRequestPath(request);
            context.verifyInteraction();
        }
    }

It throws:

org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [org.apache.hc.core5.http.HttpRequest request] in method [pactVerificationTestTemplate(au.com.dius.pact.provider.junit5.PactVerificationContext,org.apache.hc.core5.http.HttpRequest) throws org.apache.hc.core5.http.ProtocolException].

When this HttpRequest is removed it logs expected No pact found to verify

Any thoughts?

Originally posted by @fragonib in https://github.com/pact-foundation/pact-jvm/issues/768#issuecomment-1139506120

rholshausen commented 2 years ago

The problem is that to know if it can inject an HTTP request, it needs to know the type of the interaction, but there is no Pact files, so it does not know that and there won't be any request object to inject.

jamescookie commented 1 year ago

We just migrated from pact version 4.2.7 (where it was working fine without any pacts to verify) to 4.4.3 and encountered this problem.

vghero commented 1 year ago

So what changed from 4.2 to also 4.5 that this can't be detected anymore?

rholshausen commented 1 year ago

With 4.2.x, there was only one type of interaction. With 4.5.x, there can be multiple types of interactions.

holomekc commented 1 year ago

As a workaround I just added this ParameterResolver and registered it via ExtendWith to my test base class:

public class PactNoPactsWorkaround implements ParameterResolver {
    @Override
    public boolean supportsParameter(final ParameterContext parameterContext, final ExtensionContext extensionContext)
            throws ParameterResolutionException {
        final ExtensionContext.Store store = extensionContext.getStore(ExtensionContext.Namespace.create("pact-jvm"));
        final PactVerificationContext testContext = (PactVerificationContext) store.get("interactionContext");
        return testContext == null && parameterContext.getParameter().getType() == HttpRequest.class;
    }

    @Override
    public Object resolveParameter(final ParameterContext parameterContext, final ExtensionContext extensionContext)
            throws ParameterResolutionException {
        return null;
    }
}
dynnoil commented 7 months ago

I used this workaround, maybe it helps someone.

Create Junit5 extension to ignore ParameterResolutionException:

class IgnoreParameterResolutionException implements TestExecutionExceptionHandler {
    @Override
    public void handleTestExecutionException(ExtensionContext extensionContext, Throwable throwable) throws Throwable {
        if (throwable instanceof ParameterResolutionException) {
            return;
        }
        throw throwable;
    }
}

Use it on @TestTemplate method:

@TestTemplate
@ExtendWith({PactVerificationSpringProvider.class, IgnoreParameterResolutionException.class})
void pactVerificationTestTemplate(PactVerificationContext context, MockHttpServletRequestBuilder requestBuilder) {
    requestBuilder
            .with(csrf())
            .contextPath(servletContextPath);
    if (context != null) {
        context.verifyInteraction();
    }
}