Hi, I want to turn my consumer Pact test response ...
# general
n
Hi, I want to turn my consumer Pact test response body objects into mocks for unit tests. The problem I have is that these mocks will have matcher objects nested in the response dictionary (python) that my unit tests won't know how to handle. Other than avoiding using matchers like
Like
, how can I "clean" these dictionaries or otherwise use them for unit tests?
m
I can think of a few approaches. You could strip the matchers off (JS had a function to do that you could review). You could just read in the generated pact file because the examples won't have matchers in them
n
I think I prefer the idea of using the pact file. I have so far chosen to leave my pact file uncommitted, to avoid publicly committing data used in our test environment. If I continued with uncommitted pact files, I think in CI I would need to ensure consumer pact tests are run first (generating pact file), before unit test mocks can be dynamically generated via pact file.
m
one challenge with that approach, is that you would need to parse the pact file and then re-map to each test (I guess you could use the description+state to do that)
A nicer approach might be to have a
fixtures
directory with all of the payloads in there, e.g.
Copy code
fixtures
- api1.py # contains all of the interactions for the API, or scenario or however you cut it up
- api2.py
...
Then for each Pact test, you just pull them in as is with the matchers etc. already specified For other tests, you could use them also, and create a
reify
function that strips away the matchers and pact specific stuff. This way, you know the mocks used in one part of the code base can’t drift from the other
n
Ok I decided I agree after realizing I would have to run the tests in a certain order. So here is my python
reify
function:
Copy code
JsonType: TypeAlias = Union[None, int, str, bool, List[Any], Dict[str, Any]]

PactBody: TypeAlias = Union[Dict[str, Union[JsonType, Matcher]], Matcher]

def _convert_matcher_to_value(matcher: Matcher) -> JsonType:
    return matcher.generate()["contents"]


def _reify_pact_body(
    body: PactBody,
) -> JsonType:
    if isinstance(body, list):
        for index, item in enumerate(body):
            if isinstance(item, Matcher):
                body[index] = _convert_matcher_to_value(matcher=item)
            body[index] = _reify_pact_body(body=body[index])
        return body
    elif isinstance(body, Matcher):
        return _reify_pact_body(body=_convert_matcher_to_value(matcher=body))
    elif isinstance(body, dict):
        for key, value in body.items():
            if isinstance(value, Matcher):
                body[key] = _convert_matcher_to_value(matcher=value)
            body[key] = _reify_pact_body(body=body[key])
        return body
    else:
        return body