From f64bc7c2e97128559204c298ac3f3320b2321d21 Mon Sep 17 00:00:00 2001 From: Nikita Ivanov Date: Wed, 8 Jul 2026 02:35:33 +0700 Subject: [PATCH 1/3] #3: update e2e tests --- .../Clients/ArrangeClientApi.cs | 6 ++--- .../Clients/ArrangeMessages.cs | 23 ++++++++++++++++ .../Clients/CreateClientFlowTests.cs | 10 ++++--- .../Clients/StatusChangeFlowTests.cs | 21 ++++++--------- .../src/Mokkit.Example1.E2E.Tests/E2EStack.cs | 27 +++++++++---------- .../Mokkit.Example1.E2E.Tests.csproj | 11 ++++++-- 6 files changed, 61 insertions(+), 37 deletions(-) create mode 100644 example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/ArrangeMessages.cs diff --git a/example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/ArrangeClientApi.cs b/example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/ArrangeClientApi.cs index 6c5d6e1..a3bb7ba 100644 --- a/example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/ArrangeClientApi.cs +++ b/example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/ArrangeClientApi.cs @@ -1,8 +1,8 @@ using System.Net; +using Mokkit; using Mokkit.Arrange; using Mokkit.Example1.Domain.Entities; using Mokkit.Example1.E2E.Tests.Contracts; -using Capture = Mokkit.Capture; namespace Mokkit.Example1.E2E.Tests.Clients; @@ -20,9 +20,9 @@ public static class ArrangeClientApi /// the precondition couldn't be established — not the assertion under test. /// public static ITestArrange NewClient( - this ITestArrange arrange, out Capture idCapture, params ClientFieldFn[] fields) + this ITestArrange arrange, out Trapture idCapture, params ClientFieldFn[] fields) { - var capture = Capture.Start(out idCapture); + var capture = Trapture.Start(out idCapture); return arrange.Then(async host => { await host.ExecuteAsync(async http => diff --git a/example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/ArrangeMessages.cs b/example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/ArrangeMessages.cs new file mode 100644 index 0000000..41d86e1 --- /dev/null +++ b/example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/ArrangeMessages.cs @@ -0,0 +1,23 @@ +using Mokkit; +using Mokkit.Arrange; +using Mokkit.Example1.E2E.Tests.Contracts; + +namespace Mokkit.Example1.E2E.Tests.Clients; + +/// +/// Arrange helpers whose bodies are supplied by the [MokkitCapture] source generator — no hand-written +/// Trapture.Start(...) / Then(Set(new ...)) boilerplate. The generator builds the message from the +/// method's parameters (object-initializer here, since uses init properties). +/// +public static partial class ArrangeMessages +{ + [MokkitCapture] + public static partial ITestArrange ArrangeStatusChanged( + this ITestArrange arrange, + out Trapture message, + Guid clientId, + string? name, + string? email, + string? phone, + int status); +} diff --git a/example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/CreateClientFlowTests.cs b/example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/CreateClientFlowTests.cs index b920c87..79a251b 100644 --- a/example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/CreateClientFlowTests.cs +++ b/example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/CreateClientFlowTests.cs @@ -1,4 +1,5 @@ using Mokkit.Example1.Domain.Entities; +using Mokkit.Inspect; using static Mokkit.Example1.E2E.Tests.Clients.ArrangeClientApi; namespace Mokkit.Example1.E2E.Tests.Clients; @@ -16,17 +17,18 @@ public async Task Create_ViaApi_IsRetrievable_Persisted_AndAnnounced() // ACT — creating the client is the action under test; it yields the write-result artifact var result = await Act(WithName("Acme Corporation"), WithEmail("acme@e2e.test")); - // INSPECT — assert the result, then observe downstream effects by its id + // INSPECT — assert the result, capture its id once (guarded non-empty), then observe by that id await Inspect .WriteResult(result).Created() - .ApiClient(result.ClientId!.Value, c => + .Ensure(result, r => r.ClientId, out var clientId) + .ApiClient(clientId, c => { c.Name.ShouldBe("Acme Corporation"); c.Email.ShouldBe("acme@e2e.test"); c.Status.ShouldBe((int)ClientStatus.Active); }) - .DbClient(result.ClientId!.Value, c => c.ShouldNotBeNull()) - .EventPublished("clients.created", result.ClientId!.Value); + .DbClient(clientId, c => c.ShouldNotBeNull()) + .EventPublished("clients.created", clientId); } [Fact] diff --git a/example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/StatusChangeFlowTests.cs b/example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/StatusChangeFlowTests.cs index aee5fa1..8ae1daa 100644 --- a/example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/StatusChangeFlowTests.cs +++ b/example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/StatusChangeFlowTests.cs @@ -20,13 +20,17 @@ public StatusChangeFlowTests(E2EStack stack) : base(stack) [Fact] public async Task StatusChangedMessage_IsConsumed_AndReflectedEverywhere() { - // ARRANGE — a real client created through the public API + // ARRANGE — a real client created through the public API, then the status-changed message that will be + // fed to it. ArrangeStatusChanged's body is source-generated from [MokkitCapture] (see ArrangeMessages). await Arrange .NewClient(out var clientId, WithName(Name), WithEmail(Email), WithPhone(Phone), WithStatus(ClientStatus.Active)); - // ACT — an upstream system emits a status-changed message onto Kafka (carrying the full record, + await Arrange + .ArrangeStatusChanged(out var message, clientId, Name, Email, Phone, (int)ClientStatus.Suspended); + + // ACT — an upstream system emits the status-changed message onto Kafka (carrying the full record, // which the consumer validates before applying) - await Act(clientId, ClientStatus.Suspended); + await Act(clientId, message); // INSPECT — the service consumes it; the change shows up via the API (eventually — it's async), // is persisted, and a confirmation event is published @@ -36,18 +40,9 @@ await Inspect .EventPublished("clients.updated", clientId); } - private Task Act(Guid clientId, ClientStatus status) => + private Task Act(Guid clientId, StatusChangedMessage message) => Stage.ExecuteAsync>(async producer => { - var message = new StatusChangedMessage - { - ClientId = clientId, - Name = Name, - Email = Email, - Phone = Phone, - Status = (int)status - }; - await producer.ProduceAsync("clients.status-changed", new Message { Key = clientId.ToString(), diff --git a/example/Example1/src/Mokkit.Example1.E2E.Tests/E2EStack.cs b/example/Example1/src/Mokkit.Example1.E2E.Tests/E2EStack.cs index 9ecd3b8..abee33a 100644 --- a/example/Example1/src/Mokkit.Example1.E2E.Tests/E2EStack.cs +++ b/example/Example1/src/Mokkit.Example1.E2E.Tests/E2EStack.cs @@ -4,16 +4,13 @@ using DotNet.Testcontainers.Containers; using DotNet.Testcontainers.Images; using DotNet.Testcontainers.Networks; -using Microsoft.Extensions.DependencyInjection; -using Mokkit.Containers; -using Mokkit.Containers.Microsoft.Extensions.DependencyInjection; +using Microsoft.EntityFrameworkCore; +using Mokkit.Containers.Bag; using Mokkit.Example1.Db.Postgres; -using Mokkit.Example1.Db.Postgres.Options; using Mokkit.Suite; using Npgsql; using Respawn; using Respawn.Graph; -using StackExchange.Redis; using Testcontainers.Kafka; using Testcontainers.PostgreSql; using Testcontainers.Redis; @@ -108,28 +105,28 @@ public async Task InitializeAsync() _pgConnectionString = _postgres.GetConnectionString(); var apiBaseAddress = new UriBuilder("http", _api.Hostname, _api.GetMappedPublicPort(8080)).Uri; - var redisConnection = _redis.GetConnectionString(); - var external = new ServiceProviderContainerBuilder().UseInit(services => + // The lightweight Bag container just holds the pre-built external clients this suite resolves — no + // Microsoft.Extensions.DependencyInjection dependency, no auto-wiring, no options indirection. + var external = new BagContainerBuilder().UseInit(bag => { - services.AddSingleton(new HttpClient { BaseAddress = apiBaseAddress }); - services.AddSingleton>(_ => + bag.AddInstance(new HttpClient { BaseAddress = apiBaseAddress }); + bag.AddInstance>( new ProducerBuilder(new ProducerConfig { BootstrapServers = kafkaBootstrap, MessageTimeoutMs = 10000 // fail fast instead of librdkafka's 5-minute default }).Build()); - services.AddSingleton(new KafkaProbe(kafkaBootstrap)); - services.AddSingleton(_ => - ConnectionMultiplexer.Connect($"{redisConnection},abortConnect=false")); + bag.AddInstance(new KafkaProbe(kafkaBootstrap)); - services.Configure(options => options.Primary = _pgConnectionString); - services.AddPostgresDbContext(); + // Created fresh per stage and disposed when the stage ends (matching the previous scoped DbContext lifetime). + bag.AddFactory(() => new ExampleContext( + new DbContextOptionsBuilder().UseNpgsql(_pgConnectionString).Options)); return Task.CompletedTask; }); - _setup = await TestStageSetup.Create(new IDependencyContainerBuilder[] { external }); + _setup = await TestStageSetup.Create(external); await using var connection = new NpgsqlConnection(_pgConnectionString); await connection.OpenAsync(); diff --git a/example/Example1/src/Mokkit.Example1.E2E.Tests/Mokkit.Example1.E2E.Tests.csproj b/example/Example1/src/Mokkit.Example1.E2E.Tests/Mokkit.Example1.E2E.Tests.csproj index b1ec163..b97ed2a 100644 --- a/example/Example1/src/Mokkit.Example1.E2E.Tests/Mokkit.Example1.E2E.Tests.csproj +++ b/example/Example1/src/Mokkit.Example1.E2E.Tests/Mokkit.Example1.E2E.Tests.csproj @@ -14,8 +14,6 @@ - - @@ -32,6 +30,15 @@ + + + + + + + From e42bd3d9c1699f9b980a18ced253e3d9192c2d01 Mon Sep 17 00:00:00 2001 From: Nikita Ivanov Date: Sat, 11 Jul 2026 13:56:08 +0700 Subject: [PATCH 2/3] #3: migrate example est projects to latest packages 0.3.0-preview.1 --- example/Example1/Directory.Packages.props | 7 ++++--- .../Mokkit.Example1.E2E.Tests.csproj | 13 ++++--------- .../BaseIntegrationTest.cs | 1 + .../Features/Client/SaveClient/ArrangeSaveClient.cs | 10 +++++----- .../Validation/ArrangeCommand.cs | 10 +++++----- 5 files changed, 19 insertions(+), 22 deletions(-) diff --git a/example/Example1/Directory.Packages.props b/example/Example1/Directory.Packages.props index 93284d7..6306692 100644 --- a/example/Example1/Directory.Packages.props +++ b/example/Example1/Directory.Packages.props @@ -44,9 +44,10 @@ - - - + + + + diff --git a/example/Example1/src/Mokkit.Example1.E2E.Tests/Mokkit.Example1.E2E.Tests.csproj b/example/Example1/src/Mokkit.Example1.E2E.Tests/Mokkit.Example1.E2E.Tests.csproj index b97ed2a..2e131b0 100644 --- a/example/Example1/src/Mokkit.Example1.E2E.Tests/Mokkit.Example1.E2E.Tests.csproj +++ b/example/Example1/src/Mokkit.Example1.E2E.Tests/Mokkit.Example1.E2E.Tests.csproj @@ -23,6 +23,10 @@ + + + @@ -30,15 +34,6 @@ - - - - - - - diff --git a/example/Example1/src/Mokkit.Example1.Integration.Tests/BaseIntegrationTest.cs b/example/Example1/src/Mokkit.Example1.Integration.Tests/BaseIntegrationTest.cs index 5b74747..383f15f 100644 --- a/example/Example1/src/Mokkit.Example1.Integration.Tests/BaseIntegrationTest.cs +++ b/example/Example1/src/Mokkit.Example1.Integration.Tests/BaseIntegrationTest.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.Logging.Abstractions; using Mokkit.Arrange; using Mokkit.Containers; +using Mokkit.Containers.Common; using Mokkit.Containers.Microsoft.Extensions.DependencyInjection; using Mokkit.Containers.Moq; using Mokkit.Inspect; diff --git a/example/Example1/src/Mokkit.Example1.Integration.Tests/Features/Client/SaveClient/ArrangeSaveClient.cs b/example/Example1/src/Mokkit.Example1.Integration.Tests/Features/Client/SaveClient/ArrangeSaveClient.cs index 9ca48c4..b502c52 100644 --- a/example/Example1/src/Mokkit.Example1.Integration.Tests/Features/Client/SaveClient/ArrangeSaveClient.cs +++ b/example/Example1/src/Mokkit.Example1.Integration.Tests/Features/Client/SaveClient/ArrangeSaveClient.cs @@ -1,6 +1,6 @@ +using Mokkit; using Mokkit.Arrange; using Mokkit.Example1.Application.Features.Client.SaveClient; -using Capture = Mokkit.Capture; namespace Mokkit.Example1.Integration.Tests.Features.Client.SaveClient; @@ -18,7 +18,7 @@ public static class ArrangeSaveClient /// Builds a command over the defaults. public static ITestArrange CreateClientCommand( this ITestArrange arrange, - out Capture commandCapture, + out Trapture commandCapture, params ClientMutateFn[] mutateFns) { return arrange.Command(out commandCapture, SaveOperationKind.Create, clientId: null, mutateFns); @@ -27,7 +27,7 @@ public static ITestArrange CreateClientCommand( /// Builds a command targeting an existing client. public static ITestArrange UpdateClientCommand( this ITestArrange arrange, - out Capture commandCapture, + out Trapture commandCapture, Guid clientId, params ClientMutateFn[] mutateFns) { @@ -36,12 +36,12 @@ public static ITestArrange UpdateClientCommand( private static ITestArrange Command( this ITestArrange arrange, - out Capture commandCapture, + out Trapture commandCapture, SaveOperationKind operation, Guid? clientId, ClientMutateFn[] mutateFns) { - var capture = Capture.Start(out commandCapture); + var capture = Trapture.Start(out commandCapture); return arrange.Then(_ => { diff --git a/example/Example1/src/Mokkit.Example1.Unit.Tests/Validation/ArrangeCommand.cs b/example/Example1/src/Mokkit.Example1.Unit.Tests/Validation/ArrangeCommand.cs index 71a7237..6f9e0b8 100644 --- a/example/Example1/src/Mokkit.Example1.Unit.Tests/Validation/ArrangeCommand.cs +++ b/example/Example1/src/Mokkit.Example1.Unit.Tests/Validation/ArrangeCommand.cs @@ -1,7 +1,7 @@ +using Mokkit; using Mokkit.Arrange; using Mokkit.Example1.Application.Features.Client.SaveClient; using Mokkit.Example1.Domain.Entities; -using Capture = Mokkit.Capture; namespace Mokkit.Example1.Unit.Tests.Validation; @@ -16,25 +16,25 @@ public static class ArrangeCommand { public static ITestArrange SaveCommand( this ITestArrange arrange, - out Capture commandCapture, + out Trapture commandCapture, params ClientMutateFn[] mutators) => arrange.Build(out commandCapture, SaveOperationKind.Create, clientId: null, mutators); public static ITestArrange UpdateCommand( this ITestArrange arrange, - out Capture commandCapture, + out Trapture commandCapture, Guid? clientId, params ClientMutateFn[] mutators) => arrange.Build(out commandCapture, SaveOperationKind.Update, clientId, mutators); private static ITestArrange Build( this ITestArrange arrange, - out Capture commandCapture, + out Trapture commandCapture, SaveOperationKind operation, Guid? clientId, ClientMutateFn[] mutators) { - var capture = Capture.Start(out commandCapture); + var capture = Trapture.Start(out commandCapture); return arrange.Then(_ => { var data = new SaveClientData From 8843a04009eca3c13e1f05d71fb8402c111b9e03 Mon Sep 17 00:00:00 2001 From: Nikita Ivanov Date: Sat, 11 Jul 2026 15:17:07 +0700 Subject: [PATCH 3/3] #3: upgrade to .net 10, add example usage for Ensure, MokkitCapture and ThenAll --- example/Example1/Directory.Packages.props | 34 +++++++++---------- .../src/Mokkit.Example1.Api/Dockerfile | 4 +-- .../Mokkit.Example1.Api.csproj | 2 +- .../Mokkit.Example1.Application.csproj | 2 +- .../Mokkit.Example1.Common.csproj | 2 +- .../Mokkit.Example1.Db.Postgres.csproj | 2 +- .../Mokkit.Example1.Domain.csproj | 2 +- .../Clients/CreateClientFlowTests.cs | 20 ++++++----- .../Mokkit.Example1.E2E.Tests.csproj | 2 +- .../Mokkit.Example1.Infrastructure.csproj | 2 +- .../SaveClientCommandHandlerTests.cs | 10 +++--- .../Mokkit.Example1.Integration.Tests.csproj | 2 +- .../Messaging/Processor/ArrangeProcessor.cs | 22 +++++------- .../ClientStatusChangedProcessorTests.cs | 2 +- .../Mokkit.Example1.Unit.Tests.csproj | 2 +- 15 files changed, 54 insertions(+), 56 deletions(-) diff --git a/example/Example1/Directory.Packages.props b/example/Example1/Directory.Packages.props index 6306692..00f208b 100644 --- a/example/Example1/Directory.Packages.props +++ b/example/Example1/Directory.Packages.props @@ -8,26 +8,26 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/example/Example1/src/Mokkit.Example1.Api/Dockerfile b/example/Example1/src/Mokkit.Example1.Api/Dockerfile index 1a29f54..37d7505 100644 --- a/example/Example1/src/Mokkit.Example1.Api/Dockerfile +++ b/example/Example1/src/Mokkit.Example1.Api/Dockerfile @@ -1,5 +1,5 @@ # Build stage -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /src # Copy project files @@ -26,7 +26,7 @@ FROM build AS publish RUN dotnet publish "Mokkit.Example1.Api.csproj" -c Release -o /app/publish /p:UseAppHost=false # Runtime stage -FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS final +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS final WORKDIR /app # Create non-root user diff --git a/example/Example1/src/Mokkit.Example1.Api/Mokkit.Example1.Api.csproj b/example/Example1/src/Mokkit.Example1.Api/Mokkit.Example1.Api.csproj index ad982a3..48f7309 100644 --- a/example/Example1/src/Mokkit.Example1.Api/Mokkit.Example1.Api.csproj +++ b/example/Example1/src/Mokkit.Example1.Api/Mokkit.Example1.Api.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable diff --git a/example/Example1/src/Mokkit.Example1.Application/Mokkit.Example1.Application.csproj b/example/Example1/src/Mokkit.Example1.Application/Mokkit.Example1.Application.csproj index 8d95a68..17270a7 100644 --- a/example/Example1/src/Mokkit.Example1.Application/Mokkit.Example1.Application.csproj +++ b/example/Example1/src/Mokkit.Example1.Application/Mokkit.Example1.Application.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 enable enable diff --git a/example/Example1/src/Mokkit.Example1.Common/Mokkit.Example1.Common.csproj b/example/Example1/src/Mokkit.Example1.Common/Mokkit.Example1.Common.csproj index 76368e7..2ebf782 100644 --- a/example/Example1/src/Mokkit.Example1.Common/Mokkit.Example1.Common.csproj +++ b/example/Example1/src/Mokkit.Example1.Common/Mokkit.Example1.Common.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 latest enable diff --git a/example/Example1/src/Mokkit.Example1.Db.Postgres/Mokkit.Example1.Db.Postgres.csproj b/example/Example1/src/Mokkit.Example1.Db.Postgres/Mokkit.Example1.Db.Postgres.csproj index 6fa52c0..59099df 100644 --- a/example/Example1/src/Mokkit.Example1.Db.Postgres/Mokkit.Example1.Db.Postgres.csproj +++ b/example/Example1/src/Mokkit.Example1.Db.Postgres/Mokkit.Example1.Db.Postgres.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable diff --git a/example/Example1/src/Mokkit.Example1.Domain/Mokkit.Example1.Domain.csproj b/example/Example1/src/Mokkit.Example1.Domain/Mokkit.Example1.Domain.csproj index 3a63532..237d661 100644 --- a/example/Example1/src/Mokkit.Example1.Domain/Mokkit.Example1.Domain.csproj +++ b/example/Example1/src/Mokkit.Example1.Domain/Mokkit.Example1.Domain.csproj @@ -1,7 +1,7 @@  - net8.0 + net10.0 enable enable diff --git a/example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/CreateClientFlowTests.cs b/example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/CreateClientFlowTests.cs index 79a251b..ab8e89f 100644 --- a/example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/CreateClientFlowTests.cs +++ b/example/Example1/src/Mokkit.Example1.E2E.Tests/Clients/CreateClientFlowTests.cs @@ -17,18 +17,20 @@ public async Task Create_ViaApi_IsRetrievable_Persisted_AndAnnounced() // ACT — creating the client is the action under test; it yields the write-result artifact var result = await Act(WithName("Acme Corporation"), WithEmail("acme@e2e.test")); - // INSPECT — assert the result, capture its id once (guarded non-empty), then observe by that id + // INSPECT — assert the result, capture its id once (guarded non-empty), then observe the three + // independent downstream effects concurrently: the API read, the DB row and the published event. await Inspect .WriteResult(result).Created() .Ensure(result, r => r.ClientId, out var clientId) - .ApiClient(clientId, c => - { - c.Name.ShouldBe("Acme Corporation"); - c.Email.ShouldBe("acme@e2e.test"); - c.Status.ShouldBe((int)ClientStatus.Active); - }) - .DbClient(clientId, c => c.ShouldNotBeNull()) - .EventPublished("clients.created", clientId); + .ThenAll( + b => b.ApiClient(clientId, c => + { + c.Name.ShouldBe("Acme Corporation"); + c.Email.ShouldBe("acme@e2e.test"); + c.Status.ShouldBe((int)ClientStatus.Active); + }), + b => b.DbClient(clientId, c => c.ShouldNotBeNull()), + b => b.EventPublished("clients.created", clientId)); } [Fact] diff --git a/example/Example1/src/Mokkit.Example1.E2E.Tests/Mokkit.Example1.E2E.Tests.csproj b/example/Example1/src/Mokkit.Example1.E2E.Tests/Mokkit.Example1.E2E.Tests.csproj index 2e131b0..acddbe2 100644 --- a/example/Example1/src/Mokkit.Example1.E2E.Tests/Mokkit.Example1.E2E.Tests.csproj +++ b/example/Example1/src/Mokkit.Example1.E2E.Tests/Mokkit.Example1.E2E.Tests.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable diff --git a/example/Example1/src/Mokkit.Example1.Infrastructure/Mokkit.Example1.Infrastructure.csproj b/example/Example1/src/Mokkit.Example1.Infrastructure/Mokkit.Example1.Infrastructure.csproj index 02f0886..a3ec62a 100644 --- a/example/Example1/src/Mokkit.Example1.Infrastructure/Mokkit.Example1.Infrastructure.csproj +++ b/example/Example1/src/Mokkit.Example1.Infrastructure/Mokkit.Example1.Infrastructure.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable diff --git a/example/Example1/src/Mokkit.Example1.Integration.Tests/Features/Client/SaveClient/SaveClientCommandHandlerTests.cs b/example/Example1/src/Mokkit.Example1.Integration.Tests/Features/Client/SaveClient/SaveClientCommandHandlerTests.cs index a32e40f..7b7f9bd 100644 --- a/example/Example1/src/Mokkit.Example1.Integration.Tests/Features/Client/SaveClient/SaveClientCommandHandlerTests.cs +++ b/example/Example1/src/Mokkit.Example1.Integration.Tests/Features/Client/SaveClient/SaveClientCommandHandlerTests.cs @@ -1,4 +1,5 @@ using FluentValidation; +using Mokkit.Inspect; using Mokkit.Example1.Application.Features.Client.SaveClient; using Mokkit.Example1.Common; using Mokkit.Example1.Domain.Entities; @@ -21,13 +22,14 @@ await Arrange // ACT var result = await Act(command); - // INSPECT — result, real DB state (snapshot), cache refresh and published event. + // INSPECT — assert success, capture the id from the result (guarded non-empty), then observe by it. await Inspect .SaveResult(result).IsSuccess(ArrangeClient.FixedClientId) - .DbClientById(ArrangeClient.FixedClientId, out var saved, c => Assert.That(c, Is.Not.Null)) + .Ensure(result, r => r.ClientId, out var clientId) + .DbClientById(clientId, out var saved, c => Assert.That(c, Is.Not.Null)) .Verify(saved) - .CacheUpdated(ArrangeClient.FixedClientId) - .EventPublished(ArrangeClient.FixedClientId, "created"); + .CacheUpdated(clientId) + .EventPublished(clientId, "created"); } [TestCase("not-an-email", TestName = "Create_WhenEmailMalformed_FailsValidation")] diff --git a/example/Example1/src/Mokkit.Example1.Integration.Tests/Mokkit.Example1.Integration.Tests.csproj b/example/Example1/src/Mokkit.Example1.Integration.Tests/Mokkit.Example1.Integration.Tests.csproj index 4a5b6f9..ecb84a7 100644 --- a/example/Example1/src/Mokkit.Example1.Integration.Tests/Mokkit.Example1.Integration.Tests.csproj +++ b/example/Example1/src/Mokkit.Example1.Integration.Tests/Mokkit.Example1.Integration.Tests.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable diff --git a/example/Example1/src/Mokkit.Example1.Unit.Tests/Messaging/Processor/ArrangeProcessor.cs b/example/Example1/src/Mokkit.Example1.Unit.Tests/Messaging/Processor/ArrangeProcessor.cs index e8ceaad..38c4269 100644 --- a/example/Example1/src/Mokkit.Example1.Unit.Tests/Messaging/Processor/ArrangeProcessor.cs +++ b/example/Example1/src/Mokkit.Example1.Unit.Tests/Messaging/Processor/ArrangeProcessor.cs @@ -1,3 +1,4 @@ +using Mokkit; using Mokkit.Arrange; using Mokkit.Example1.Application.Features.Client.SaveClient; using Mokkit.Example1.Common; @@ -10,7 +11,7 @@ namespace Mokkit.Example1.Unit.Tests.Messaging.Processor; /// Arrange building blocks for the status-changed processor — build (and capture) the incoming message and /// configure the substituted save handler the processor resolves from its DI scope. /// -internal static class ArrangeProcessor +internal static partial class ArrangeProcessor { public static ITestArrange IncomingStatusChange( this ITestArrange arrange, @@ -21,21 +22,14 @@ public static ITestArrange IncomingStatusChange( return arrange.Then(_ => capture.Set(KafkaMessageFaker.NewStatusChanged(status: status))); } - public static ITestArrange IncomingStatusChangeMissingContact( + // Body supplied by the [MokkitCapture] source generator: it object-initializes the message from the + // parameters (ClientId, Status) and leaves the unmentioned contact fields (Name/Email/Phone) null. + [MokkitCapture] + public static partial ITestArrange IncomingStatusChangeMissingContact( this ITestArrange arrange, out Capture messageCapture, - int status) - { - var capture = Capture.Start(out messageCapture); - return arrange.Then(_ => capture.Set(new ClientStatusChangedMessage - { - ClientId = Guid.NewGuid(), - Name = null, - Email = null, - Phone = null, - Status = status - })); - } + Guid clientId, + int status); public static ITestArrange HandlerSucceedsFor( this ITestArrange arrange, diff --git a/example/Example1/src/Mokkit.Example1.Unit.Tests/Messaging/Processor/ClientStatusChangedProcessorTests.cs b/example/Example1/src/Mokkit.Example1.Unit.Tests/Messaging/Processor/ClientStatusChangedProcessorTests.cs index 4263577..609d12d 100644 --- a/example/Example1/src/Mokkit.Example1.Unit.Tests/Messaging/Processor/ClientStatusChangedProcessorTests.cs +++ b/example/Example1/src/Mokkit.Example1.Unit.Tests/Messaging/Processor/ClientStatusChangedProcessorTests.cs @@ -65,7 +65,7 @@ public async Task NullContactFields_MapToEmptyStrings() { // ARRANGE await Arrange - .IncomingStatusChangeMissingContact(out var message, (int)ClientStatus.Inactive) + .IncomingStatusChangeMissingContact(out var message, Guid.NewGuid(), (int)ClientStatus.Inactive) .HandlerSucceedsFor(message); // ACT diff --git a/example/Example1/src/Mokkit.Example1.Unit.Tests/Mokkit.Example1.Unit.Tests.csproj b/example/Example1/src/Mokkit.Example1.Unit.Tests/Mokkit.Example1.Unit.Tests.csproj index 6ef3f50..0ba2843 100644 --- a/example/Example1/src/Mokkit.Example1.Unit.Tests/Mokkit.Example1.Unit.Tests.csproj +++ b/example/Example1/src/Mokkit.Example1.Unit.Tests/Mokkit.Example1.Unit.Tests.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable