2

I am working with multiple applications that communicate asynchronously using Kafka. These applications are managed by several departments and contract testing is appropriate to ensure that the messages used during communication follow the expected schema and will evolve according to the contract specification.

It sounded like the pact library for python is a good fit because it helps creating contract tests for HTTP and message integrations.

What I wanted to do is to send an HTTP request and to listen from the appropriate and dedicated Kafka topic immediately after. But it seems that the test is forcing me specify an HTTP code even if what I am expecting is a message from a queue without an HTTP status code. Furthermore, it seems that the HTTP request is being sent before the consumer is listening. Here is some sample code.

from pact.consumer import Consumer as p_Consumer
from pact.provider import Provider as p_Provider
from confluent_kafka import Consumer as k_Consumer


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

config = {'bootstrap.servers':'server', 'group.id':0, 'auto.offset.reset':'latest'}
consumer = k_consumer(config)
consumer.subscribe(['usertopic'])

def user():   
  while True:
    msg = consumer.poll(timeout=1)
    if msg is None:
      continue
    else:
      return msg.value().decode()

class ConstractTesting(unittest.TestCase):
  expected = {
  'username': 'UserA',
  'id':123,
  'groups':['Editors']
  }  

  pact.given('UserA exists and is not an administrator')
  .upon_receiving('a request for UserA')
  .with_request(method='GET',path='/user/')
  .will_respond_with(200, body=expected)
  
  with pact:
    result = user()
  
  self.assertEqual(result,expected)

How would I carry out contract testing in Python using Kafka? It feels like I am going through a lot of hoops to carry out this test.

Zeruno
  • 1,391
  • 2
  • 20
  • 39

1 Answers1

3

With Pact message it's a different API you write tests against. You don't use the standard HTTP one, in fact the transport itself is ignored altogether and it's just the payload - the message - we're interested in capturing and verifying. This allows us to test any queue without having to build specific interfaces for each

See this example: https://github.com/pact-foundation/pact-python/blob/02643d4fb89ff7baad63e6436f6a929256c6bf12/examples/message/tests/consumer/test_message_consumer.py#L65

You can read more about message pact testing here: https://docs.pact.io/getting_started/how_pact_works#non-http-testing-message-pact

And finally here are some Kafka examples for other languages that may be helpful: https://docs.pactflow.io/docs/examples/kafka/js/consumer

Matthew Fellows
  • 3,669
  • 1
  • 15
  • 18
  • Thank you. I am able to understand Pact much better now. I did not know that Message Pacts were available on the Python version. Could you please help me understand how in the first code sample, that the contract is being read from? In the typical pact example, one can call pact.start_service() or pact.setup() to work with the mock Pact Broker, but when pact is a MessagePact, it is not possible to call these functions as they are not attributes of MessagePact. – Zeruno Nov 27 '21 at 21:16
  • The first example is the consumer side which is generating the pact, here is the provider version: https://github.com/pact-foundation/pact-python/blob/02643d4fb89ff7baad63e6436f6a929256c6bf12/examples/message/tests/provider/test_message_provider.py#L83 – Matthew Fellows Nov 28 '21 at 23:14
  • What I meant is that the code in your first link https://github.com/pact-foundation/pact-python/blob/02643d4fb89ff7baad63e6436f6a929256c6bf12/examples/message/tests/consumer/test_message_consumer.py#L65 I am understanding is testing whether the contract is generated sucessfully or not. Aren't I suposed to be able to read an already existing contract and test that it is being withheld/ that the message is as expected? – Zeruno Nov 29 '21 at 13:36
  • If we look at the consumer test here, https://docs.pact.io/implementation_guides/python/readme the result is being compared against the expected. But the link you have sent me only checks that the contract is formed. I am trying to understand why this difference exists? – Zeruno Nov 29 '21 at 15:58