pact-foundation / pact-net

.NET 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://pact.io
MIT License
823 stars 225 forks source link

Dynamic date in request #495

Closed onno-amsterdam closed 3 months ago

onno-amsterdam commented 3 months ago

Hi Pact-net, I have a question I hope you can help with.

In my contract I have this Post request body:

{
"startDate": "2024-04-01"
}

The provider is expecting and only accepting a date in the future. Is there a way to make sure the date in the contract is always in the future? Of course I can work with a date that's far in the future but still that's not as robust as I would hope.

Hope you can help & thank you!

adamrodger commented 3 months ago

Pact is about testing the "shape" of the data rather than any business logic. That means testing that the date is a string and matches a particular format (e.g. via checking against a regex).

The canonical example is writing a contract for a service which allows you to reset your password. Typically passwords have certain requirements such as "must contain a capital letter" etc.

The reason you don't test the logic is that the logic can change over time but the contract won't. The password will always be a string, but what's considered a valid password will change. The contract should therefore only ever confirm that the password is a string.

You use things like provider states and stubs on the provider end to configure the provider to respond appropriately. For example you may use a provider state of "given the password is valid" which configures the provider to accept the next submitted password, or "given the password is invalid" to reject it (e.g. by returning a HTTP 400 response).

So yeah, that's what you need to do here - use provider states to configure the provider to accept the date in one interaction and reject it in another interaction so you can verify the response in both cases.

onno-amsterdam commented 3 months ago

Thank you Adam for your quick response!

I do use provider states and a ProviderStateController and I stub a service layer in my application. However in front of that is a validator that is called immediately after the controller get's called. So I guess indeed there's a little logic involved.

Your answer is clear, thank you. I will reconsider my approach.

Op di 26 mrt 2024 om 20:55 schreef Adam Rodger @.***>:

Pact is about testing the "shape" of the data rather than any business logic. That means testing that the date is a string and matches a particular format (e.g. via checking against a regex).

The canonical example is writing a contract for a service which allows you to reset your password. Typically passwords have certain requirements such as "must contain a capital letter" etc.

The reason you don't test the logic is that the logic can change over time but the contract won't. The password will always be a string, but what's considered a valid password will change. The contract should therefore only ever confirm that the password is a string.

You use things like provider states and stubs on the provider end to configure the provider to respond appropriately. For example you may use a provider state of "given the password is valid" which configures the provider to accept the next submitted password, or "given the password is invalid" to reject it (e.g. by returning a HTTP 400 response).

So yeah, that's what you need to do here - use provider states to configure the provider to accept the date in one interaction and reject it in another interaction so you can verify the response in both cases.

— Reply to this email directly, view it on GitHub https://github.com/pact-foundation/pact-net/issues/495#issuecomment-2021344617, or unsubscribe https://github.com/notifications/unsubscribe-auth/AJWKWFKWLMADHVA3QHBUEGDY2HAATAVCNFSM6AAAAABFJRR4PGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMRRGM2DINRRG4 . You are receiving this because you authored the thread.Message ID: @.***>

mefellows commented 3 months ago

Adam - in the spec there is a ProviderState generator that allows the provider to replace a dynamic value like this during verification:

matcher Spec Version example configuration description
ProviderState V4 {"expression": "/api/user/${id}", type": "ProviderState"} Generates a value that is looked up from the provider state context using the given expression

It's designed for this very purpose.

It is technically supported by the V3 spec (via the extendable generators feature), and is documented in the V4 spec here: https://github.com/pact-foundation/pact-specification/tree/version-4?tab=readme-ov-file#supported-generators

The compatibility suite test case is here: https://github.com/pact-foundation/pact-compatibility-suite/blob/4a3c411cd5ae23b1491b9e89619ed1bbc7558df1/features/V3/http_generators.feature#L6

This blog post elaborates on the use case: https://pactflow.io/blog/injecting-values-from-provider-states/.

I would suggest we re-open this as a feature enhancement for the V4 implementation, or create a separate tracking issue for the features in V4.