"Understand, verify, or (rarely) extend an Outbox Relay host integration test in a CoreEx *.Test.Relay project. USE FOR: understanding the templated RelayTests.cs shape, verifying the relay forwards outbox events to the broker, hosted-service pause/resume endpoint checks, diagnosing Service Bus emulator entity-not-found failures. DO NOT USE FOR: API host tests (use coreex-test-api), Subscribe host tests (use coreex-test-subscribe), the relay host's Program.cs/hosted-service setup (see coreex-host-setup.instructions.md)."
Install
npx skillscat add avanade/coreex/coreex-test-relay Install via the SkillsCat registry.
CoreEx: Outbox Relay Host Integration Test
Guides you through the *.Test.Relay project — the most templated and least-extended of the three
integration test projects. Unlike API/Subscribe tests, which grow one file per entity/subscriber as a
domain evolves, relay tests are largely generic plumbing checks generated by CoreEx.Template and
rarely need new scenarios per domain.
When to Use
- Understanding what
RelayTests.csalready verifies before assuming it needs extending - Verifying the relay forwards outbox-written events to the broker end-to-end
- Adding a hosted-service pause/resume/status check
- Diagnosing a Service Bus emulator "entity not found" test failure
- The rare case where a domain has relay behavior beyond the generic forward-and-verify flow (e.g. a
custom hosted-service management endpoint)
When Not to Use
- API host integration tests — use
coreex-test-api - Subscribe host integration tests — use
coreex-test-subscribe - Relay host
Program.cs/ hosted-service registration — see `/.github/instructions/coreex-host-setup.instructions.md`
Resolve project-wide choices from state before asking. Read the solution-root
AGENTS.md
Feature Configuration:messaging-providergates this skill (a Relay host exists only when a
messaging provider is configured) anddata-provider(PostgreSQL vs SQL Server vs Cosmos) selects the outbox
publisher family (PostgresOutboxPublisher/SqlServerOutboxPublisher/CosmosDbEventPublisher) — never mix them. Only prompt
for what is unrecorded; re-state resolved values for confirmation.
Quick Reference
- Base class:
WithApiTester<{Domain}.Relay.Program>— relay hosts have no FusionCache; do not callClearFusionCacheAsync()here - No business-data seeding needed for relational forwarding tests — write directly to the outbox via
Test.ScopedType<ExecutionContext>and a provider-specific outbox publisher (PostgresOutboxPublisher/SqlServerOutboxPublisher). Cosmos requires provisioned business/lease containers and an outbox event paired with a business mutation in the same transaction. - Assert delivery via
Test.GetAndClearAzureServiceBusAsync(...)against the expected topic/subscription — or, for a command, the target domain queue:Test.GetAndClearAzureServiceBusAsync(ServiceBusSessionReceiverOptions.CreateForQueue("{destination}-{target}"))(the queue must exist in Test.CommonServiceBus.GetQueues(); seecoreex-command-publish-e2e) - Hosted-service management endpoints are also testable over plain HTTP —
/hosted-services/{name}/pause,/resume, etc. - Check existing coverage before extending it — relational hosts usually need only
RelayTests.cs+OtherTests.Health.cs+OtherTests.HostedServices.cs. Cosmos tests should cover every outbox-hosting container, cleanup, the first-start/checkpoint policy, and pause/resume.
public class RelayTests : WithApiTester<YourDomain.Relay.Program>
{
[OneTimeSetUp]
public async Task OneTimeSetUpAsync()
=> await Test.ResetAzureServiceBusAsync(Common.ServiceBus.GetQueues(), Common.ServiceBus.GetTopicsAndSubscriptions()); // Test.Common ServiceBus: the code-based topology.
[Test]
public async Task Outbox_Relay()
{
Test.ScopedType<ExecutionContext>(test =>
{
test.Run(async _ =>
{
var pub = ActivatorUtilities.GetServiceOrCreateInstance<PostgresOutboxPublisher>(test.Services); // or SqlServerOutboxPublisher — provider-specific relational example
pub.Add("{solution}", [ce1, ce2]);
await pub.PublishAsync();
for (int i = 0; i < 5; i++)
await Task.Delay(TimeSpan.FromSeconds(1));
var list = await Test.GetAndClearAzureServiceBusAsync(
ServiceBusSessionReceiverOptions.CreateForTopicSubscription("{solution}", "{domain}"));
list.Should().HaveCount(2);
}).AssertSuccess();
});
}
}Test.Http()
.Run(HttpMethod.Post, "/hosted-services/postgres-outbox-relay-03/pause")
.Response.StatusCode.Should().Be(HttpStatusCode.Accepted);For Cosmos relay tests, publish via CosmosDbEventPublisher inside CosmosDbUnitOfWork.TransactionAsync(...), paired with a real business mutation, and use bounded polling to assert broker delivery and outbox cleanup. Keep the relay's default IEventPublisher registered as its broker destination. Provision containers before accessing the tester: even Test.Configuration constructs the host and captures its first-start boundary. Use a test-owned observation subscription and do not reset containers beneath a running change-feed processor. The Customers sample below demonstrates both PartitionKey.None and explicit partition keys.
Troubleshooting — Service Bus Emulator "Entity Not Found"
If a Relay (or any Service Bus) test fails with:
The messaging entity 'sb://sbemulatorns.servicebus.onebox.windows-int.net/<topic>/subscriptions/<subscription>' could not be found.the test host reached the emulator but the topic/subscription doesn't exist in it. This is an
environment problem, not a test-code defect — check that the Service Bus emulator container is
running, and that the test resets the entities via Test.ResetAzureServiceBusAsync(Common.ServiceBus.GetQueues(), Common.ServiceBus.GetTopicsAndSubscriptions())
(in a templated solution the emulator /servicebus/Config.json is intentionally empty; the entities are defined in the Test.Common ServiceBus class). Do not "fix" it by editing the test, subject names, or emulator entity names.
Key References
- `/.github/instructions/coreex-tests.instructions.md` — full, authoritative test conventions, "Outbox Relay Host Tests" section
coreex-test-api/coreex-test-subscribe— the other two integration test skills, both more likely to need per-domain extension than this one- Illustrative examples (CoreEx sample — not present in your project):
- RelayTests.cs — canonical outbox-forwarding test
- Customers RelayTests.cs — Cosmos two-container forwarding, cleanup, first-start exclusion, and management checks
- OtherTests.Health.cs, OtherTests.HostedServices.cs — health and hosted-service management checks