Skip to main content

Custom Adapter

Extend XceptoAdapter to create a user-facing domain test DSL. The adapter is registered once per test, has a lifecycle, and exposes methods that return fluent builders or register steps.

Minimal example

public sealed class MyServiceAdapter : XceptoAdapter
{
private readonly MyServiceClient _client;

public MyServiceAdapter(MyServiceClient client)
{
_client = client;
}

// Simple atomic action — always transitions immediately
public void PerformAction(Action action)
{
AddStep(new LambdaState("Perform action",
onEnter: _ => action(),
condition: _ => true));
}

// Expectation — retried until matched
public void ExpectEvent(Predicate<MyEvent> predicate)
{
AddStep(new LambdaState("Expect event",
onEnter: _ => { },
condition: _ => _client.PollEvent(predicate)));
}

protected override Task Initialize(IServiceProvider sp) => Task.CompletedTask;
protected override Task Cleanup() => Task.CompletedTask;
}

Lifecycle

MethodWhen it runs
Initialize(IServiceProvider)Before the state machine starts; after all adapters are registered
Cleanup()After the state machine finishes or fails; always runs

Prefer returning builders

For configurable domain operations, return a builder identity instead of registering a step directly. This lets the test chain multiple fluent calls before the step is built:

public sealed class DomainAdapter : XceptoAdapter
{
private readonly DomainClient _client;

public DomainAdapter(DomainClient client) { _client = client; }

// Returns a builder — test chains .WithName().ShouldHaveStatus(...)
public EntityFlowBuilder Entity(string entityId)
{
return new EntityFlowBuilder(Builder)
.WithEntityId(entityId)
.WithClient(_client);
}
}

Adapter builder

Pair the adapter with a configuration builder that registers it:

public sealed class DomainAdapterBuilder
: AbstractAdapterBuilder<DomainAdapterBuilder, DomainAdapter>
{
private DomainClient _client = new();

public DomainAdapterBuilder(IStateMachineBuilder builder) : base(builder) {}

public DomainAdapterBuilder WithClient(DomainClient client)
{
_client = client;
return this;
}

public override DomainAdapter Build()
{
var adapter = new DomainAdapter(_client);
StateMachineBuilder.RegisterAdapter(adapter);
return adapter;
}
}

// Extension method for ergonomic access
public static class TransitionBuilderExtensions
{
public static DomainAdapterBuilder DomainAdapterBuilder(
this TransitionBuilder builder)
=> new(builder);
}