You simply create a change and in the footer say
Depends-On: <pull request URL/gerrit URL/gitlab URL/etc>
Zuul will pull everything together, merge it all, and provide your tests with repos on disk that reflect the entire dependency chain. You write your test to install/run/etc. from these repos that have been prepared for you. The test might have only your change, or it might have 20 other changes; Zuul handles all this. This way you test everything together.
You don't need to spend resources speculatively running every possible combination; most changes probably don't affect each other (when you know they do; setup dependencies). But the trick is, you don't commit, Zuul does. It puts all approved changes in a queue, merges them and runs the "gate" tests. It does this in a smart way to try and batch as much as possible. When they pass, it commits the change. When something fails; either it won't merge with HEAD, or it's tests fail against HEAD, it gets rejected and you fix it up and go through the cycle again. It's impossible to commit anything broken to HEAD, because everything that is committed has been tested.
Our code structure needs to support both the functionality required by our customers, and our needs as developers.
[1] https://blog.mergify.io/announcing-speculative-merge-queues
In practice, I feel it is much easier to assign work and organize your codebase so that logically-different business functions can be managed in isolation.
We rarely have merge conflicts these days, and we are also on 1 big monorepo. It mostly boils down to discipline and architecture.