(Starting a new thread since this is a somewhat di...
# general
j
(Starting a new thread since this is a somewhat different topic) - I have a messaging use case where a service consumes a message and emits one or more messages in response, which are in turn consumer by other services. I can use pact to assert that the consumed message is as expected, but I'd also like to assert that the emitted messages are as expected, based on the consumed message, similar to how pact works with Http request/response tests. Here's a diagram to illustrate what I mean. The labels on the left indicate how each service emits messages that are derived from the message it consumes. But really, this is similar to a request/response flow, which the labels on the right illustrate. I'd like to be able to verify this type of situation by asserting the incoming messages (requests) and the emitted messages (responses) for each service. Any thoughts on this? Is there a way to accomplish this?
t
Pact doesn't do this, but I think it should. You might be able to put something together that does it by wrapping the message pact interfaces, but it would be custom. I'm working on an alternative framework that will support this (and ideally be pact-compatible), but it's not ready for use yet.
j
Interesting, can you ping me when there's something to share? Either here or jonathan@elastic.co.
As I thought more about this, I think it's fair to want to test this type of use case, but I'm not sure if a contract test is the appropriate place to do it. Because when service A sends a message to service B, it's true that service B emits a "response", but that response flows down to service C rather than back up to service A. So who/where would the assertion of that response live?
t
It depends. There's an analogy to DB requests, like an http request to get a resource might. result in a request to a DB. You'd have a contract where you say: http request -> http response and you could have another contract where you say DB request -> DB response (for example - we don't actually have DB contract tests). You wouldn't want: http request -> DB request
But, you might have a different case, where eg a translation layer for messages - where you might say: some message -> http request
For me, this comes back to the contract test is for "can these two services talk to each other"
j
Yea that's a good point, though I did read in the guidelines that the DB example gets into the realm of functional testing, where shouldn't care about whether a DB is involved. That makes sense to me.
šŸ’Æ 1
t
I think the general case that you're hitting here is: some request -> some response But sometimes that's asynchronous
j
Yea, it's asynchronous, and the "response" flows down to another service rather than back to the originator of the first message (which makes it more of a reaction than a response).
šŸ‘ 1
t
So, the contract of "can my http client talk to the http server" doesn't include "did the http server make the right DB call"
Similarly, "can Service A understand the message it gets" won't include "did it send a message to Service B", for most cases
āž• 1
Translation layers are a really good counterexample here - like:
Copy code
Client -> BFF -> Backend request
where say the BFF does passthrough, or a slight payload refactor
In that case "did I send the right request further down" is actually part of the contract, I think
āž• 1
"Can the client and the BFF understand each other" can't really be answered by the BFF - it depends on whether the BFF and the backend can understand each other
pact doesn't handle this especially comfortably at the moment
j
The catch is that we don't want Service A to know anything about what Service B might emit. But we do want to assert that Service B emits something appropriate when it consumes a message from Service A.
Which is why I wasn't sure if that particular assertion should be part of a contract test. Maybe it's just a unit test inside Service B.
So a unit test would assert that an input results in some outputs as expected, and contract tests would assert that those outputs are compatible with the next service(s) down the line.
šŸ’Æ 1
t
But we do want to assert that Service B emits something appropriate when it consumes a message from Service A.
Right! I wouldn't do this with the contract test from service A, unless it's part of the communication with service A
j
...we just wouldn't be able to contract test anything across more than 2 services at a time.
t
like, it's probably an expectation of service A (eg, hey service B, please save this in your storage)
In most cases, I would do: • Contract test on Service A with the message it receives, confirming that it unmarshals into the expected business object • Unit test in Service A that confirms that the expected business object would be processed into a request for Service B (probably I mock the service B message sending client completely at this point) • Contract test in Service A that covers the code that was mocked in the previous step
šŸ‘ 1
Not sure how clear that description is, sorry šŸ˜•
j
Yea that makes sense.
t
So a unit test would assert that an input results in some outputs as expected, and contract tests would assert that those outputs are compatible with the next service(s) down the line.
Yes. You could equivalently say that a contract test asserts that an input (the call to the client code & the actual request on the wire) produces the expected output (returned business object from unmarshalling the actual response on the wire). That is, a contract test is a unit test that crosses service boundaries.
šŸ‘ 1