HI guys! Reading about Pact and thinking about usi...
# general
n
HI guys! Reading about Pact and thinking about using it. I have a simple usecase (I think). I want to write a test that sends http to external service, record the request-response in pact json format, then replace the external service in the test with pact-mock-server. I think it must be one of the simplest uses but I can't figure how to register the request-response in pact format. Is there a way to launch pact-proxy-server that would forward my requests and record them against responses?
t
afaik, Pact doesn’t do this, at least not easily. Matt and I were discussing this kind of feature a while back - it would be an awesome way to kickstart your tests (you could even just run the app for a while in some kind of “watch mode”, and generate a test skeleton)
One subtlety that you might miss if you’re new to Pact is that a key part of a pact test is confirming that the response object correctly unmarshalls into whatever business object your API client returns. In some languages (eg JS), this is usually the same as the json object - but not always. This part would be hard to automate.
If I were going to do this, I would write something that watched the response, and then autogenerated the pact test in whatever DSL I wanted.
n
Hmm, I don't understand the confirming part. I write in Rust and what I want really is to make my tests fast - so replace the external service with a mock service. Since I know how to interpret the response from external service and deserialize it into my types I should be able to do the same with pact responses too. Pact has a mock server as far as I understand that would spit reponses based on its json configuration and those responses would be identical to external service. Or I get it wrong?
t
A successful pact test says: “This consumer will make this request, and can understand this response, if the provider sends it”
Without asserting on the resulting object from your API code, you can’t be sure that the response is correctly understood
(For comparison, a successful provider verification- ie, the other side of the pact test - says “this provider can understand that request, and will generate a response that the consumer understands”
Usually in pact you write the expectations first- so you would write down what your consumer expects to receive from the provider in your pact test. Then you later verify that expectation
It would be possible to seed that process by observing real traffic, but I think it’s rare to already have those tests ready to be watched.
There are a few other subtleties too - in a Pact test, you ideally don’t describe the whole payload, just the parts your consumer needs. This is advantageous because it’s not a breaking change to rename or remove a field/endpoint that no-one is using. You wouldn’t have this advantage with recorded traffic- although not having it won’t matter in a lot of cases.
You’re right that a Pact test will be much faster than an integration test. This is one of the major advantages, I think.
Pact has a mock server as far as I understand that would spit reponses based on its json configuration
Ohh, are you asking how to configure the mock service yourself? I probably wouldn’t do this.
It’s likely to be more trouble than it’s worth, I think.
I don’t think the mock setup json is documented.
If you wanted to try this, you’d have to look at the Rust source to see how they’re read, or something like pact-js, which has the matchers laid out in a fairly readable way.
n
I just want to use the library functions
create server
start server
Providing the pact file to the server
The pact file ideally I want it to be autogenerated by running "pact proxy server"
t
I’m not personally familiar with the rust API, sorry
n
that doesn't exist yet unfortunately as I understand
Thank you very much for taking time and writing replies
Much appreciated!
t
hmm. The pact file shouldn’t exist yet, in that design.
n
It doesn't exist in the beginning
t
If you have a pact file, it means you definitely can send those requests and understand those responses
n
But I would like to autogenerate it
t
Yes, it should be autogenerated.
n
But how can I autogenerate it?
t
usually the consumer tests generate it.
The mock server has a
write_pact_file
function
which will do it - although I think you have to check to make sure that all the tests pass before calling it, otherwise you’ll write a pact file that might not be true
Anyway, it sounds like an interesting project. I’d be keen to hear if you get anything working like this
I’d recommend starting with the user-facing DSLs first, though.
that will give you a feel for how it usually works, which will help inform any automation
n
Ok so I did this repo to solve this problem https://github.com/NikZak/pact-proxy-rs
m
looking at this, are you not better off re-using existing record/replay tools, instead focussing on writing a converter to/from the common formats?
e.g. VCR -> Pact, Nock -> Pact, Polly -> Pact etc.?
that way, you don’t have to re-invent the record/replay bit?
Also I do think you need to be careful - in this way, you’ll miss out on the benefits of matchers and provider states, two very powerful aspects of Pact, without which will likely make your tests very brittle
…and of course, the unit testing bit Tim mentioned
I like to think of Pact as a unit testing tool for your API client, which also happens to do contract testing. If you think of it this way, you’ll be less focussed on generating a contract (and all that goes with that), and more about the test itself
n
Hi Matt. Thanks a lot for looking at this and chiming in. It is very possible that I still don't understand all of the strenghts of pact. To me the important part here was to make my tests effortlessly fast. I just replace the target url with this proxy server and then it records pacts and matches to this pacts in the next call. First run takes seconds, second run microseconds which is what I need. After some research and asking around I did not find anything like that. I am happy to add back all the missing features one by one if it is required. Or use something standard. (but it should not be that I write the whole request/expected response inside the test like everywhere proposed, that already exists in multiple versions) Would be great if you give some more detailed feedback. Possibly as issues on github. I believe that converters are needed if you want to connect to the web to get the info first time. And I had to rewrite some of the functionality of pact_mock_server to make matching faster (before it was taking >90% of program time) and to be able to interpret a modified url localhost:port/https/<url you actually need in the web without the scheme>
as for existing record/replay. Initially it was my intention but found nothing suitable in rust
I thought of using non rust stuff with test-containers. but it has own drawbacks too
Imagine I have a connector to the exchange that sends orders, reads market data, etc. I have to test it. I can not change the client, I would lose functionality interpreting incoming data. So i can not use some vcr client or whatever client. All I can "dependency inject" is the url and it's for the server to take all the work from here
so no other changes on the client side are allowed. could not find a solution for that
t
. (but it should not be that I write the whole request/expected response inside the test like everywhere proposed, that already exists in multiple versions)
I think … you need this, right? How would you avoid writing it out? Or, would it be better to automatically translate whatever expectation you already have into Pact?
n
well I do avoid writing it out. Just look at the example in the readme. I don't write out the expectation. I write whatever I receive as expectation into a pact and then use it as expectation when test is launched second time. I guess I fail to explain my use case.