Is there a good way to mock a pact provider servic...
# pact-python
j
Is there a good way to mock a pact provider service's dependencies during the verification run? I want to seed my fake db with test data when I run my setup functions, but because of the way our service is designed, it is reaching out to other services to get auth data and other such things tangentially related to the contract I'm trying to verify, so even with the fake data the contract is expecting, I'm not accessing that data when the pact verifier runs because the user that it's using can't be retrieved because the pact provider service can't reach the auth service. The traditional methods of mocking that I'm familiar with are all for running unit tests though (like the pytest_mock's MockerFixture.patch, for example) and while I could overwrite the config that contains the base url of the auth service and run another mock server to return the expected user data whenever it's called, that seems like it'll wind up being a lot of extra work and it seems like there's got to be another better solution.
The issue I think is that the pact verifier process is in a weird half-way point between the production app and the unit test app. We have a very unit-testable extension of our app already built out for the purpose of our pytest suite which mocks out all the external dependencies, but for the pact verification we want to run the actual instance of the provider service. On the other end of the spectrum though is the production-ready provider service, which is what the provider verification process is running (plus the additional route for posting states obviously). But this service doesn't have any mocks built out or any special testing logic because it's assumed it runs in a live environment with other external services which it can actually call.
m
Thinking of the config with the url, would it work without too much extra to add in endpoints to the service when verifying? I'm thinking similar to how in the examples it adds a route for the state endpoint and behaviour there - you could add another auth endpoint so something can get called and just do nothing, then at least it's all in one place together 🤔
Alternatively, maybe in the state handler, you could just monkey patch out the actual methods that go and do the auth No clue how nice it would be as a pattern
😄
j
I'm not exactly a python expert. Can you monkey-patch a function that's being imported into a class? So it's not an attribute on the class itself...
m
It gets quite messy and is easy to end up with it not working but yes you should be able to, I'd need to dig out some examples to explain better [it's easy to import from somewhere, but then not mock correctly if you import differently where you're doing the mocking]
j
Like I may have:
Copy code
from function_lib import helper_function

class ThingDoer:
    def do_thing(self):
        value = helper_function()
        # < snip out lots of logic on the value >
        return value
I get how one might monkey patch
do_thing()
function, but not how to monkey patch over the
helper_function()
call, which is ultimately the bit I want to overwrite
m
I will dig out some examples and get back to you in a bit, just on a call now 🙂
j
Cool, thank you
m
Right, so: I have some code which for the "get_auth" goes and uses boto to talk to AWS and get credentials, this is in
bearly_utils/ig.py
in a completely separate package in my test code I can then do:
Copy code
from bearly_utils import ig
and later:
Copy code
class MockIgAuth(NamedTuple):
    identifier: str
    password: str
    key: str
    environment: str = "demo"


@pytest.fixture
def patch_bearly_utils(monkeypatch):
    def get_auth(account):
        account_json = json.loads(account)
        mock_account = account_json["account"]["mock"]
        return MockIgAuth(
            identifier=mock_account["identifier"], password=mock_account["password"], key=mock_account["key"]
        )

    monkeypatch.setattr(ig, "get_auth", get_auth)
The key bit with the monkeypatch is you are importing something as
ig
, and where you're using it for real, you have the same import line.... I mean here if I had just
import bearly_utils
and then tried to do
bearly_utils.ig.get_auth
it wouldn't match up with the monkeypatched one. I hope that makes sense 😄 When it's used in the actual non-test code it's called like:
Copy code
auth = ig.get_auth(account=account)
j
How do you use pytest fixtures in your provider verification?
m
Hmm, that one's separate from Pact usage, there isn't actually Pact in where that mocking is happening
I'm not quite sure what you mean by "how" though?
Where I'm currently using Pact is message rather than "normal" http, and it was less effort to use requests-mock in multiple places to mock out the calls than monkeypatch them, so I haven't followed that approach here
j
Maybe I didn't make my original question clear then. I'm trying to mock out the auth package which my provider service consumes when I'm verifying a pact for this provider. Since the pact verifier script does not use pytest, I don't know how to mock dependencies without it, so I'm stuck
m
ohhh ok, I thought as you mentioned pytest that you were using it
j
I wish, that would solve a lot of problems
I assumed it wasn't possible to use pytest for provider verification though
m
it's been a while since using unittest, if you mean you're using that instead?
j
For my provider verification? How would that work?
m
pact-python/examples/fastapi_provider is using pytest
I may be completely misunderstanding or missing something, apologies if so 😅 How are you currently verifying then?
j
I run my provider service, then I run the "verify provider" cli and point it at this provider's host/port and provide the pactfile (etiher as a url or as a file path)
I see, you're not using the verifier cli
you're doing everything in pytest and starting the server as a fixture 🤔
m
yeah, the run_pytest rather than verify_pact route
j
shoot, I'd have to re-write a lot to do it this way now...
m
Huge disclaimer around I'm not in any way saying it's the best or even better way 🙂
I think that could still work going back to the original suggestion around doing something in the provider state
j
I thought it would be easier from the perspective of our CI/CD pipeline if the provider logic was the same, so I based it on the verifier cli
m
if the provider logic was the same
same as? in principle i like the idea of a nice and consistent calling a cli if that's what you meant, but I've gone for wrapping it up everywhere so my ci/cd does a "make test" regardless of what it is where possible (again, it's an approach, rather than necessarily being the best route)
j
Same as our Java services and our Node services
m
using cli verifier you mean? makes sense
👍 1
I can maybe try and play with some code later, but I think you should be able to just monkey patch like that from the provider state handler in exactly the same way 🤔 Ignore that it's in a fixture, you just have an alternative method call that returns something which you're patching in
how was that almost a week ago 😮 did you manage to get anywhere in the end?
j
I got something working. I didn't want to have to rewrite everything to utilize pytest, so I just wrote a handful of mocks manually and managed to get them to work so 👍
👍 1