Intropy.Framework.Testing 0.3.0-beta.1

This is a prerelease version of Intropy.Framework.Testing.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package Intropy.Framework.Testing --version 0.3.0-beta.1
                    
NuGet\Install-Package Intropy.Framework.Testing -Version 0.3.0-beta.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Intropy.Framework.Testing" Version="0.3.0-beta.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Intropy.Framework.Testing" Version="0.3.0-beta.1" />
                    
Directory.Packages.props
<PackageReference Include="Intropy.Framework.Testing" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Intropy.Framework.Testing --version 0.3.0-beta.1
                    
#r "nuget: Intropy.Framework.Testing, 0.3.0-beta.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Intropy.Framework.Testing@0.3.0-beta.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Intropy.Framework.Testing&version=0.3.0-beta.1&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Intropy.Framework.Testing&version=0.3.0-beta.1&prerelease
                    
Install as a Cake Tool

Intropy.Framework.Testing

Hand-rolled fakes and delivery helpers for component integration tests against the Intropy framework. No mocking-framework dependency, no ASP.NET dependency, no Dapr sidecar required.

The package fakes the four edges every component integration test fakes, plus a helper for delivering CloudEvents to loader endpoints exactly as a Dapr sidecar does:

Helper Namespace Fakes
InMemoryFileAdapter Intropy.Framework.Testing.Adapters IFileAdapter (source/destination connectors)
FakeTopic<TCtx> Intropy.Framework.Testing.Topics The extractor's Dapr pub/sub publish step
FakeIdempotencyServiceClient Intropy.Framework.Testing.Services IIdempotencyServiceClient
FakeBusinessIncidentServiceClient Intropy.Framework.Testing.Services IBusinessIncidentServiceClient
DaprDelivery Intropy.Framework.Testing.Delivery Sidecar CloudEvents delivery to loader endpoints
PublishedMessageCapture Intropy.Framework.Testing.Dapr Publish-call capture for DaprClient substitutes

The canonical pattern

  1. Build the component's pipeline/host exactly as production composition does — same steps, same builder calls.
  2. Fake the edges:
    • Extractors: ExtractorBuilder<...>.WithSender(fakeTopic) in place of WithDaprTopicPublisher(...).
    • Loaders: override the keyed IFileAdapter registration with an InMemoryFileAdapter, and the two service clients with their fakes (plain DI override — last registration wins).
  3. Assert on fake state: topic count/events, adapter files, recorded incidents/resolutions and commits, delivery acks.
// Extractor test shape
var topic = new FakeTopic<MyContext>();
var pipeline = MyExtractorComposition.BuildPipeline(
    extractorBuilder => extractorBuilder.WithSender(topic));

await RunSweep(pipeline, fileAdapter); // component's own orchestration

Assert.Equal(2, topic.Count);
Assert.Equal("order.created", topic.Events[0].Type);
// Loader test shape (WebApplicationFactory with DI overrides)
var client = factory.CreateClient();
var ack = await client.DeliverAsync("/events/orders", cloudEvent);

Assert.Equal(DeliveryAck.Success, ack);
Assert.Equal(expectedJson, destinationFiles.GetString("out/order-42.json"));

Fake semantics (fail like production)

  • InMemoryFileAdapter — missing reads throw FileNotFoundException (the Dapr binding throws; it never returns null); deletes of missing files no-op (binding delete is idempotent); files are keyed on the effective path (basePath/fileName when a write passes an override). Pass a basePath to the constructor to make ListAsync mirror LocalFileAdapter: only files under that path, listed by file name. ReadException / WriteException / DeleteException simulate a dead source/destination. Per-file faults: AddUnreadableFile(name) seeds a file that is listed but throws on read (corrupt source file), and SetDeleteException(name, ex) makes deletes fail for one file while others succeed — the publish-succeeds-but-delete-fails path, where the file is re-processed next run and idempotency must catch it.

  • FakeTopic<TCtx> — captures the exact CloudEvent instances the real publisher would have encoded. SendException surfaces as a technical failure through the framework's normal exception handling, matching a dead broker.

  • Service fakes — faults throw the typed IdempotencyServiceException / BusinessIncidentServiceException. Typing matters: the framework's incident router has a dedicated catch for BusinessIncidentServiceException; any other exception type takes a different code path than production.

  • DaprDelivery.DeliverAsync — POSTs the structured-mode envelope as application/cloudevents+json and parses the {"status": "..."} ack. Unknown, missing, or malformed statuses map to DeliveryAck.Retry, matching the sidecar's fail-safe redelivery. DeliveryAck members map to wire values as SuccessSUCCESS, RetryRETRY, DropDROP.

  • PublishedMessageCapture — records publish calls made through a DaprClient substitute configured by your test project (works with any mocking framework; one wiring line per fake). Assert on the captured PublishedMessages and decode envelopes via DecodeCloudEvent():

    var daprClient = Substitute.For<DaprClient>();
    var capture = new PublishedMessageCapture();
    daprClient
        .PublishByteEventAsync(
            Arg.Any<string>(), Arg.Any<string>(), Arg.Any<ReadOnlyMemory<byte>>(),
            Arg.Any<string?>(), Arg.Any<Dictionary<string, string>?>(), Arg.Any<CancellationToken>())
        .Returns(Task.CompletedTask)
        .AndDoes(ci => capture.Capture(
            ci.Arg<string>(), ci.ArgAt<string>(1), ci.ArgAt<ReadOnlyMemory<byte>>(2),
            ci.ArgAt<string?>(3)));
    
    // ... run the pipeline ...
    
    var message = capture.Messages.Single();
    Assert.Equal("orders", message.TopicName);
    Assert.Equal("order-42", message.DecodeCloudEvent().Subject);
    

Loader ack/consumption matrix

This matrix describes the behavior of framework-composed loader and transactional pipelines (which acks their endpoints/handlers produce), not of this package. DaprDelivery only delivers the envelope and parses the ack.

Scenario Ack Side effects
Valid message SUCCESS File written to destination
Duplicate (idempotency Ignore) SUCCESS Nothing written
Business-rule violation SUCCESS Incident routed — consumed, never retried
Destination throws RETRY Nothing written
Idempotency service down (StatusException) RETRY Technical failure
Malformed envelope RETRY No incident routed

Business failures are consumed. When a business step fails, the framework's incident-router finalizer triggers the incident and returns Success(defaultValueFactory()) — for framework-wired extractors an empty CloudEvent, never null. Do not assert on null result values; assert on Incidents instead.

Extractor sweep matrix

Scenario Published Source file
Valid Yes Deleted
Duplicate (idempotency Ignore) No Still deleted
Validation failure Incident routed Consumed (empty-CloudEvent success)
Technical failure (SendException / ReadException) No Left for the next run

Notes

  • Thread-safe: all recorded state is lock-guarded and exposed as snapshots, so parallel extractor sweeps cannot corrupt assertions. Fault knobs (ReadException, SendException, ...) are volatile — safe to toggle between runs, not a coordination primitive for mid-run assertions.
  • Versioned in lockstep with the framework packages.
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.3.0-beta.5 57 8/12/2026
0.3.0-beta.1 63 8/11/2026