Skip to content

Introduction

Mokkit is a test-orchestration toolkit for .NET and for Go. It doesn’t replace your test framework, your mocking library, or your DI container — it sits on top of them and gives your tests a shape and a language.

That language is the whole point.

Good tests describe a scenario. Read one aloud and it should sound like a sentence someone on the team would say:

Given a new client Acme Corporation that’s already in the cache, when we create it, then the API returns Created, the row is in the database, and a clients.created event is published.

BDD tools like Cucumber and SpecFlow chase that readability with a separate language — Gherkin feature files, plus “step bindings” that glue each English phrase to some C# behind the scenes. You get prose, but you pay for it: a second syntax, a runtime binding layer, and steps that can drift out of sync with the code without the compiler noticing.

Mokkit takes the other road. The same scenario, as a Mokkit test:

await Arrange
.NewClient(out var client, WithName("Acme Corporation"))
.CacheHasClient(client);
var result = await Act(client);
await Inspect
.WriteResult(result).Created()
.Ensure(result, r => r.ClientId, out var id)
.ApiClientMatches(id, name: "Acme Corporation")
.DbClientExists(id)
.EventPublished("clients.created", id);

It reads like the sentence above — but there is no DSL. NewClient, CacheHasClient, Created, ApiClientMatches, EventPublished are just methods you wrote, in your language: your project’s testing vocabulary. Because it’s plain code, you get everything the compiler and IDE give you — autocomplete, go-to-definition, rename-refactoring, and the guarantee that a test that doesn’t make sense won’t compile.

Every Mokkit test follows the same three-phase story (Arrange-Act-Assert, with the assert phase named Inspect):

  • Arrange — set up the world and capture the artifacts later steps refer to.
  • Act — perform the one thing under test; it yields a result.
  • Inspect — observe the outcome. Inspect only reads; it never changes state.

Each phase is a fluent chain of the verbs you defined. See Arrange / Act / Inspect for the mechanics and Building your test vocabulary for the part that matters most.

Mokkit began in C# and was ported to Go, and the port is a translation rather than a transliteration: the shape, the vocabulary discipline and the composition model carry over, while each side speaks its language natively.

C# Go
Chains deferred, run by await eager — a verb has already run when it returns
Artifacts out var captures (Captures) typed tokens (Tokens)
Interaction asserts mock library’s own, plus Satisfied()-style pull-forward same idea, per adapter
Failure phases Inspect wraps Assert.Multiple Inspect fails soft natively
API reference DocFX pkg.go.dev

Pages on this site teach both: shared concepts show the same example in a C#/Go tab pair (your choice sticks as you navigate), and the few ideas that exist in only one language carry a badge in the sidebar.

Mokkit assumes nothing about the rest of your stack:

  • Test framework — xUnit, NUnit, MSTest, TUnit — or Go’s testing; Mokkit is just calls inside your test functions.
  • Mocking — first-class adapters for Moq, NSubstitute and FakeItEasy in C#; gomock, mockery/testify and minimock in Go (or bring your own).
  • DI containerMicrosoft.Extensions.DependencyInjection, Autofac, Castle Windsor in C#; samber/do and uber-go/dig in Go; or the dependency-free Bag container both sides ship for tests that just need to hold a few instances.

The same vocabulary and the same test shape carry from a fast, fully-mocked unit test to an integration test against a real database, up to a black-box end-to-end test that boots your whole system in Docker. The guides walk each of those.

  • Why Mokkit? — the honest comparison with BDD/DSL frameworks.
  • Installation — the packages and how to pick them.
  • Quickstart — a complete test in a few minutes.