Skip to content

Quickstart

This walks through a full (if tiny) Mokkit test with xUnit and NSubstitute. See Installation for the packages.

A service with one dependency we’ll want to substitute:

public interface IEmailSender
{
Task SendWelcome(string address);
}
public sealed class SignupService(IEmailSender email)
{
public async Task<Guid> Register(string address)
{
await email.SendWelcome(address);
return Guid.NewGuid();
}
}

The Stage is where your services live during a test. Here we use the dependency-free Bag container to hold a substitute and the service under test — the same substitute instance goes into both, so we can drive it and verify it:

using Mokkit.Containers.Bag;
using Mokkit.Suite;
using NSubstitute;
public sealed class SignupTests
{
private static async Task<TestStage> NewStage()
{
var email = Substitute.For<IEmailSender>();
var setup = await TestStageSetup.Create(
new BagContainerBuilder()
.AddInstance(email)
.AddInstance(new SignupService(email)));
return setup.EnterStage();
}
}

An Inspect verb is a C# extension method that observes an outcome. This one reads “a welcome email was sent to…”:

using Mokkit.Inspect;
public static class SignupVocabulary
{
public static ITestInspect WelcomeEmailSent(this ITestInspect inspect, string toAddress) =>
inspect.Then(host => host.Execute<IEmailSender>(email =>
email.Received(1).SendWelcome(toAddress)));
}

Now the test reads as Arrange → Act → Inspect. (This one needs no arrange.)

[Fact]
public async Task Registering_a_user_sends_a_welcome_email()
{
var stage = await NewStage();
// ACT — the Act phase resolves the service, runs the one thing under test, and returns its result.
var id = await stage.Act().Returning(host =>
host.ExecuteAsync<SignupService, Guid>(service => service.Register("acme@example.com")));
// INSPECT — observe the outcome through your vocabulary.
await stage.Inspect()
.WelcomeEmailSent("acme@example.com");
Assert.NotEqual(Guid.Empty, id);
}
  • TestStageSetup.Create(...) composed your containers; EnterStage() gave you a fresh Stage for the test.
  • stage.Act().Returning(...) started the Act phase, resolved the service from the stage, ran it, and returned its result.
  • stage.Inspect().WelcomeEmailSent(...) ran your Inspect verb, which resolved the same IEmailSender from the stage and verified the call.

The verb WelcomeEmailSent is the seed of your project’s vocabulary. As you add Arrange verbs (to set up state) and more Inspect verbs (to observe it), tests become short, readable compositions of sentences — with full IDE and compile-time support.