A write lands in the database
The API answers 201 Created, but did the order reach the database with the right status? The test creates it over REST, then reads the row itself — on a database the run started, shared with the in-process application.
The same journey runs in the demo — DomainAccessJourney.cs writes through REST and reads the committed row through the test-side SQL connection; Setup.cs composes both sides over the same store. The full API surface is in SQL.
Compose
protected override void Configure(IProtoHostBuilder builder) =>
builder
// One PostgreSQL for the run; the application reads its connection string from this key.
.AddInfrastructure(PostgresDatabase.Container(), "ConnectionStrings:Orders")
.AddApplication("Api", app => app
.AddAspNetCoreServer<Program>()
.AddRest(rest => rest.AddClient("Api")))
// The test's own connection, to the same database.
.AddSql(
services => new NpgsqlConnection(
services.GetRequiredService<ProtoInfrastructureSettings>()
.Values["ConnectionStrings:Orders"]),
sql => sql.Isolation = SqlIsolation.None)
.AddEntityFrameworkCore<OrdersDbContext>((services, options) =>
options.UseNpgsql(services.GetRequiredService<DbConnection>()));
OrdersDbContext is the application's own context, so the test reads the row with the same mapping the application wrote it with. Configure it here rather than calling a host AddDbContext<OrdersDbContext> afterwards — EF Core keeps the first options registration and drops later ones.
The test
[Application("Api")]
public sealed class OrderPersistenceTests
{
[ProtoTest]
public async Task A_created_order_is_stored_as_pending()
{
var reference = $"ORD-{Proto.Context.TestId}";
using var response = await Proto.Context.Rest()
.Body(new { reference, product = "notebook", quantity = 2 })
.PostAsync("/api/orders");
response.Should.HaveHttpStatus(HttpStatusCode.Created);
var stored = await Proto.Context.Sql<OrdersDbContext>().Orders
.AsNoTracking()
.SingleAsync(order => order.Reference == reference);
Assert.Multiple(() =>
{
Assert.That(stored.Status, Is.EqualTo(OrderStatus.Pending));
Assert.That(stored.Quantity, Is.EqualTo(2));
});
}
}
What it proves
The assertion is about the row the application committed — not the request body echoed back. Proto.Context.Sql<T>() resolves the scoped context over the test's connection, so the read runs in the same context the trace records next to the REST call.
Limits
- Why
SqlIsolation.None. The in-process application opens its own connection and commits; a rollback on the test's connection would not undo that write. With the defaultTransactionisolation the run-start guard throws while an application registered throughAddApplicationis not declared withShareConnectionWith(...)— and a declaration is only a statement, not enforcement. See Isolation. - Unique values, not cleanup. The container lives for one run, so nothing survives to the next one. Within a run, a reference built from
TestIdkeeps parallel tests out of each other's rows. - No SQL tracing. The connection and transaction lifecycle is traced; individual commands are not.
- Against a deployed environment the suite usually cannot reach the database. Compose
AddSqlonly where it can, and mark the test[RequiresCapability(ProtoCapabilityKinds.Store)]: where no store is composed, it skips instead of failing.