skip to content

In Pact, what does an asynchronous message pact verify, and what does excluding the transport leave unproven?

level: middleimportance: must knowfreq 62%

answer

  1. It is about a payload, not a pipe
  2. No infrastructure runs on either side
  3. Description, states, contents, metadata
  4. Emitter code out, handler code in
  5. Topic names appear nowhere in the file

basics

~20 s

An asynchronous Pact message pact verifies that a producer emits a payload the named consumer's handler can decode. It covers payload shape and message metadata only. Topic, broker, delivery and serialization on the wire stay unproven.

solid answer

~40 s

A message pact records one **asynchronous interaction**: a description that names it, optional provider states, the expected contents, message metadata such as a content type, and matching rules. On the consumer side the test feeds the recorded contents straight into the real handler; on the provider side the verifier asks the producer's code for the same named message and replays the matchers against what comes back. No topic, exchange, broker or delivery ever runs. So the guarantee is narrow and precise: *if* the producer emits this payload and *if* the handler receives it, the handler decodes it. Routing, subscription filters, serializer configuration, headers added by infrastructure, ordering and delivery are outside the pact and need their own thin integration test.

code

json · 18 lines
json
{
  "messages": [
    {
      "description": "a slot-booked event for donor 40817",
      "providerStates": [
        { "name": "donor 40817 has a confirmed slot" }
      ],
      "contents": {
        "donorId": "40817",
        "centreCode": "BR-217",
        "bookedAt": "2026-03-11T09:24:00Z"
      },
      "metaData": {
        "contentType": "application/json"
      }
    }
  ]
}

go deeper

for a junior

Recall that contract testing is not only for HTTP: Pact can record an event as a message pact. Knowing the name and that no broker is involved is enough at this level.

for a middle

Be ready to list what a recorded message contains — description, provider states, contents, metadata, matching rules — and to state plainly that the transport is absent from all of it.

for a senior

An interviewer expects you to name what the exclusion costs in production and say how you cover it instead: routing, subscription filters, serializer wiring and delivery each need an owner outside the pact suite.

for a principal

Own the argument for where the boundary sits across many teams: which guarantees the contract suite carries, which the platform carries as topology checks, and how you stop teams reading a green pact wall as proof that events flow.

## The artefact: what an asynchronous message pact holds A **message pact** is a JSON file recorded by a consumer's test run, exactly like an HTTP pact, but its unit of recording is an *event* rather than a request/response pair. Each recorded message carries four things: a **description** that uniquely names the interaction ("a slot-booked event for donor 40817"), zero or more **provider states**, the expected **contents** (the payload body), and **message metadata** such as a content type or a routing key. Matching rules sit alongside the contents so that a field can be pinned by type or by regex rather than by literal value. Pact Specification V3 keeps these in a top-level `messages` array, separate from the `interactions` array an HTTP pact uses. Pact Specification V4 folds everything into one `interactions` array where each entry declares its own type, so an `Asynchronous/Messages` interaction and a `Synchronous/HTTP` interaction can be recorded in the same pact file. Notice what is *not* in that list. There is no URL, no topic name, no exchange, no queue, no partition, no consumer group, no acknowledgement mode and no delivery guarantee. The pact is a statement about a **payload**, not about a pipe. ## The two halves of the guarantee The consumer half runs first. The consumer's test declares the message it expects, and Pact hands the recorded contents straight to the consumer's real handler function. If the handler decodes the payload and produces the domain object the test asserts on, the pact is written. The provider half runs later, usually on the producer's build. The verifier reads the pact, applies the named provider state, then asks the producer's own code to produce the message with that description on demand and compares what comes back against the recorded matchers. Put together, a green message pact says exactly this: **the code that emits this event produces a payload that the code that handles it can decode.** That is a real, valuable and frequently broken guarantee — and it is the whole guarantee. ## What the excluded transport costs you | Question about production | Answered by a message pact? | | --- | --- | | Can the consumer's handler decode this payload? | Yes | | Does the producer's code emit that payload for this state? | Yes | | Is the field the consumer reads still populated? | Yes, if a matcher pins it | | Is the event published to the destination the consumer subscribes to? | No | | Do the serializer, headers and framing survive a real round trip? | No | | Is the event delivered, in order, within a deadline? | No | | Does the consumer's subscription filter let the event through? | No | The exclusion is deliberate, not an oversight. Because no messaging infrastructure is involved, both halves run in milliseconds in ordinary unit-test time, neither side needs the other to be running, and the two builds never have to be sequenced. That is precisely why contract tests scale to a large fan-out where end-to-end event tests do not. The cost is that a team must consciously own the excluded part somewhere else — typically one thin integration test per service that publishes and consumes for real, and a naming or topology check in the platform. A message pact suite that is treated as covering "the events work" is a false sense of safety. ## Where teams get burned 1. **Renaming the destination.** A blood-donation scheduling service moved its slot-booked event from one topic to a versioned successor. All 9 consumer pacts stayed green — none of them mentions a topic — and 3 of the 9 consumers silently received nothing for two days. 2. **Recording the payload from a fixture.** If the producer-side verification returns a hand-written JSON string rather than calling the real emitter, the pact proves that two test fixtures agree. Wire the verification to the production emitter. 3. **Assuming metadata covers broker headers.** The metadata recorded in the pact is what the producer's application code sets. Headers injected by the client library or the broker are not in the pact and are not compared. 4. **Assuming serialization is covered.** If the event is Avro or Protobuf on the wire but the pact records the decoded JSON view, a serializer or codec misconfiguration is entirely outside the contract. ## How to phrase this in an interview Lead with the narrow claim — payload in, payload out, no pipe — then name one thing the exclusion buys you (independent, fast, unsequenced builds) and one thing it costs you (routing, delivery and serialization need their own test). Candidates who describe a message pact as "an end-to-end test for events" have not run one.

  • A slot-booked event moves to a new topic name. Would any message pact fail?
    No. A destination name is not recorded in a message pact at all, so every pact on both sides stays green while the routing is broken. Destination and subscription topology have to be covered elsewhere — a per-service publish-and-consume integration test, or a platform-level topology check that compares declared producers and subscribers.
  • If the event is Avro on the wire, what part of that does a message pact cover?
    Only whatever the pact actually records. If the pact records a decoded JSON view of the payload, it proves the two sides agree on fields and shape, and proves nothing about the codec, the writer configuration, or the bytes on the wire. Teams that need the encoded form covered either record the encoded payload or keep a separate serialization test.
  • Does a green message pact let you delete your end-to-end event test?
    It lets you shrink it, not delete it. The payload agreement no longer needs an end-to-end run, so one thin test per service that publishes and consumes for real is usually enough to cover routing, serializer wiring and subscription filters. What you stop paying for is a combinatorial suite that re-proves payload agreement for every producer-consumer pair.

It is a spec for the shape of a parcel and the shape of the letterbox, agreed without ever posting anything: it proves the parcel fits, not that the postal service delivers it.

saying these in an interview costs you the question

  • Calls a message pact an end-to-end test for events
  • Believes the topic or queue name is recorded
  • Thinks a broker must be running to verify
  • Assumes delivery and ordering are covered
  • Says serialization on the wire is always included