pact-python
pact-python copied to clipboard
Matchers not working according to docs
Hello, I want to use the matchers in my consumer tests but using them is kinda weird. The way that I would expect them to work according to docs is:
event = {
"event": "delivery:created",
"delivery_type": matchers.Term("express|standard", "standard"),
}
(
pact_no_publish.given("Delivery has standard shipping")
.expects_to_receive("delivery:created")
.with_content(event)
.with_metadata({"Content-Type": "application/json"})
)
What this does is to pass the Term object into the message.
What I have to do in this case is this:
event = {
"event": "delivery:created",
"delivery_type": matchers.Term("express|standard", "standard").generate()["data"]["generate"],
}
This works but is the same as passing in a string directly and defeats the purpose of the matcher.
Thanks for the report, and that doesn't seem right to me at all. Are you able to provide a repro we can use to look at this?
P.S. matchers.Term("express|standard", "standard")
- I think you are looking for an enum-like matcher here.
You probably actually want matchers.Term("^express|standard$", "standard")
which will match the exact value. It's unlikely those words are going to be a subset of others, but you might want to know that for future matching.
Sure, here it is: https://github.com/MdotMertens/python-pact-matchers
In it I reproduced the bug by using the Like matcher. It passes the matcher into my consumer function instead of an actual value.
Ah, thanks! I see the problem.
In other languages, the event would have the matchers stripped. This can be done via the reify
command on the pact-message
command.
with pact_no_publish:
handler(event=event, context={})
I don't know Python very well, but ideally the with pact_no_pubish
would provide the reified (body without matchers etc.) to the block, so that handler
could be invoked with the cleaned JSON blob, and not with the matchers.
It should be fairly straightforward in the meantime to create a utility function that recurses the event
object and detects the presence of matchers, and extracts the value. Then your test should work as expected, and the matching rules will be properly serialised into the contract:
with pact_no_publish:
reified_event = reify(event)
handler(event=reified_event, context={})
This is a bug, IMO, or at the very least, we should provide instructions as to how to use this better.
Had a go at it and the code was actually pretty straight forward. The implementation for this was even there it was just not used.
The context manager does nothing for it and the unit tests are a knit a bit too tightly for implementing it in the context manager, since this would require a lot of change. It just handles cleaning up the test, there is nothing that gets setup when entering the conetxt.
Would love to get some feedback and to get this merged/improved. 😄
@MdotMertens, you can make it work by calling matchers.get_generated_values(event)
, this will return a "reified" version of event
that you can pass into your handler.