Actual interactions do not match expected interactions for mock MockService

4.7k views Asked by At

I'm new to both python and contract testing. I'm trying to test my consumer application using pact-python.

This is the test file test_posts_controller.py

import unittest
import atexit
from pact import Consumer, Provider, Term
import requests

pact = Consumer('Consumer').has_pact_with(Provider('Provider'))
pact.start_service()
atexit.register(pact.stop_service)

class GetPostsContract(unittest.TestCase):
    def test_get_all_posts(self):
        expected = {
            "userId": 1,
            "id": 1,
            "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
            "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
        }

        (pact
            .given('posts exist')
            .upon_receiving('a request for post by id')
            .with_request('GET', '/posts/1')
            .will_respond_with(200, body=expected))

        with pact: 
            result = requests.get('https://jsonplaceholder.typicode.com/posts/1')

        self.assertEqual(result.json(), expected)

Here I'm trying to hit JSONPlaceholder.

I'm using pytest command to run the test.

But I'm getting the below error. I don't know what i'm missing.

self = <pact.pact.Pact object at 0x10cc8c8d0>

def verify(self):
    """
    Have the mock service verify all interactions occurred.

    Calls the mock service to verify that all interactions occurred as
    expected, and has it write out the contracts to disk.

    :raises AssertionError: When not all interactions are found.
    """
    self._interactions = []
    resp = requests.get(
        self.uri + '/interactions/verification',
        headers=self.HEADERS)
    >       assert resp.status_code == 200, resp.text
    E       AssertionError: Actual interactions do not match expected interactions for mock MockService.
    E
    E       Missing requests:
    E           GET /posts/1
    E
    E       See pact-mock-service.log for details.

    venv/lib/python3.7/site-packages/pact/pact.py:209: AssertionError

I have tried pact.setup() and pact.verify() also but still I'm getting the same error. Can someone help me fix this?

And it doesn't create pactfile also. What are the things I have to setup?.

3

There are 3 answers

0
Timothy Jones On BEST ANSWER

How to find out why it's happening

AssertionError: Actual interactions do not match expected interactions for mock MockService.

^ This error says that the pact mock didn't receive the interactions that were described in the Pact test.

E       Missing requests:
E           GET /posts/1

^ This part says that the mock didn't receive a GET request for /posts/1. If the mock server had received other requests (eg a POST that it wasn't expecting), they would also be listed here.

So, we know that no requests hit the mock server during the test.

Reading the rest of the test class, we have:

    with pact: 
        result = requests.get('https://jsonplaceholder.typicode.com/posts/1')

This shows that the test is hitting jsonplaceholder.typicode.com instead of the mock set up during the test. So, the error is correct - to fix it we need to hit the mock server:

How to fix it

To fix your case, you'll need to contact the pact mock server instead:

    with pact: 
        result = requests.get('https://localhost:1234/posts/1') 

(Or whatever port you have configured Pact to listen on).

You can also get this directly from Pact:

    with pact: 
        result = requests.get(pact.uri + '/posts/1') 

How to learn more

You might find this diagram of a consumer test useful (taken from the How Pact Works section of the Pact documentation):

Consumer test

Your consumer code is the orange part, and the blue part is the mock provided by Pact.

During a Pact test, the consumer doesn't contact the actual provider, it only contacts the mock provider. The reverse is true for a provider verification - only the mock consumer contacts the real provider.

This means you don't need to spin up the consumer and provider together in order to test. This advantage is a major selling point of contract testing.

0
Abhishek D K On

hostname and port can be provided to override the default
http://localhost:1234 mock-service URL
example:

pact = Consumer('Consumer').has_pact_with(Provider('Provider'), port='<port>', host_name='<host>')  
0
J_A_X On

Pact is telling you that the interaction never got triggered. You never call GET /posts/1 on the pact mock server, hence when you try to verify it, it'll say that it's missing the interaction and not product a pact file since it failed.

Unless https://jsonplaceholder.typicode.com/posts/1 points to the pact mock service (which I'm guessing it's not), this won't work. Whatever the port it's on (it's normally on localhost:), is what you need to hit.

Instead of the code you did, get the base URI from pact itself:

with pact: 
    result = requests.get(pact.uri + '/posts/1')

self.assertEqual(result.json(), expected)
pact.verify()