# Test Harness Foundation

## Goal

Write deterministic MassTransit tests for consumers, sagas, and request/response behavior.

## Agent enforcement rules

### Do

- Use `AddMassTransitTestHarness` and start one harness per scenario.
- Assert behavior with async harness collections and targeted consumer/saga harnesses.
- Set explicit test timeouts to fail fast.

### Do not

- Do not reuse one harness across unrelated scenarios.
- Do not write unbounded assertions without terminal operators.
- Do not rely on transport-only assertions without business outcome checks.

## Build checklist

- Use `AddMassTransitTestHarness` and `ITestHarness`.
- Start harness once per test scenario.
- Assert with async harness collections (`Consumed`, `Sent`, `Published`).
- Add targeted harness checks (consumer harness, saga harness) for behavior-level validation.
- Use `SetTestTimeouts` for faster failing tests.

## Example: consumer test

```csharp
[Test]
public async Task Submit_order_should_be_consumed_and_publish_event()
{
    await using var provider = new ServiceCollection()
        .AddMassTransitTestHarness(x =>
        {
            x.AddConsumer<SubmitOrderConsumer>();
        })
        .BuildServiceProvider(true);

    var harness = await provider.StartTestHarness();

    await harness.Bus.Publish(new SubmitOrder(InVar.Id, "123"));

    Assert.That(await harness.Consumed.Any<SubmitOrder>(), Is.True);
    Assert.That(await harness.Published.Any<OrderSubmitted>(), Is.True);

    var consumerHarness = harness.GetConsumerHarness<SubmitOrderConsumer>();
    Assert.That(await consumerHarness.Consumed.Any<SubmitOrder>(), Is.True);
}
```

## Example: request/response test with a handler

```csharp
[Test]
public async Task Request_should_receive_response()
{
    var request = new GetOrderStatus(InVar.Id);

    await using var provider = new ServiceCollection()
        .AddMassTransitTestHarness(cfg =>
        {
            cfg.Handler<GetOrderStatus>(async context =>
            {
                await context.RespondAsync(new OrderResponse("OK"));
            });
        })
        .BuildServiceProvider(true);

    var harness = await provider.StartTestHarness();

    var client = harness.GetRequestClient<GetOrderStatus>();
    var response = await client.GetResponse<OrderResponse>(request);

    Assert.That(response.Message.Status, Is.EqualTo("OK"));
}

public record GetOrderStatus(Guid OrderId);
public record OrderResponse(string Status);
```

## Example: faster timeout tuning

```csharp
services.AddMassTransitTestHarness(cfg =>
{
    cfg.SetTestTimeouts(testTimeout: TimeSpan.FromSeconds(30), testInactivityTimeout: TimeSpan.FromSeconds(5));
});
```

## Guardrails

- Do not reuse one harness for unrelated scenarios.
- Do not use unbounded `Select/SelectAsync` assertions without a terminal operator.
- Do not assert only transport-level events; verify business side effects too.

## Verification

- `dotnet build`
- `dotnet test --filter Harness`
- `dotnet test --filter Consumer`

## References

- [Unit Testing Guide](/guides/unit-testing)
- [Consumer Unit Testing Guide](/guides/unit-testing/consumer)
- [Saga Unit Testing Guide](/guides/unit-testing/saga)
