mocking without the nonsense
Burla ("prank" in Italian) is a lightweight, LLM‑friendly mocking library for .NET. It is built for explicit tests, strict defaults, and real migrations between mocking styles and libraries. Its API stays focused and predictable: setup, argument matching, and verification follow consistent patterns, so humans can read tests quickly and LLMs can spend their context on the code under test instead of mock-library quirks. Start with one awkward test, see how it reads, and use the migration guides when you want to scale up. Burla stays free forever. Yes, really. No prank this time.
Install from NuGet with dotnet add package Burla.
| Pain Point | Moq | NSubstitute | Burla |
|---|---|---|---|
IAsyncEnumerable |
Helper methods needed | Helper methods needed | First-class support |
| Ref/Out parameters | Verbose delegates | Limited support | Clean syntax |
| Strict mode | Opt-in | ❌ | Default ✅ |
| Thread safety | ❌ | ❌ | Built-in ✅ |
| Runtime instance access | ✅ (.Object) |
direct substitute | ✅ (.Instance; .Object compatibility alias) |
| Clear verification | ✅ | ✅ | ✅ |
// Create a mock
var mock = Mock.Of<ICalculator>();
// Setup behavior
mock.Setup(x => x.Add(Arg.Any<int>(), Arg.Any<int>())).Returns(42);
// Use it
var result = mock.Instance.Add(1, 2); // returns 42
// Verify calls - use standard xUnit assertions!
var calls = mock.CallsTo(x => x.Add(1, 2));
Assert.Single(calls); // called exactly onceThis "query and assert" pattern (inspired by MELT) is the Burla-native verification style. Verify(...) and Times remain available mainly for low-diff Moq migrations and for VerifyNoOtherCalls().
Burla-native docs use .Instance as the everyday spelling for the runtime double. .Object stays available as a compatibility alias for Moq-style code and migration work.
Burla also ships with analyzer/code fixes grouped into BURLA01x compatibility nudges and BURLA02x correctness checks. Today that means .Object -> .Instance (BURLA010), It.* -> Arg.* (BURLA011), SetupGet(...) -> Setup(...) (BURLA012), and a quick fix for forgotten zero-argument Times parentheses in Verify(...) (BURLA020). If you are migrating a large Moq codebase and want less noise, lower the compatibility rules BURLA010, BURLA011, and BURLA012 to silent or none in .editorconfig.
Most users can just install Burla and go. If you need something more specialized, Burla.Core is the runtime-only package and Burla.Analyzers is available on its own for suggestion/code-fix-only installs.
If you only need the runtime instance and not the wrapper later, especially in setup-only or NSubstitute-style tests, Mock.Create<T>() and Mock.CreateLoose<T>() return it directly. Compatibility sugar such as It, SetupGet(...), .Object, and Verify(..., Times...) exists for low-friction migrations, while the main docs keep teaching Arg, Setup(...), .Instance, SetsByRefParameter(...), Event(...).Emit(...), and CallsTo(...) + standard assertions first.
Burla's 1.0 surface stays focused:
- create mocks with
Mock.Of<T>()/Mock.OfLoose<T>(), or return the runtime value directly withMock.Create<T>()/Mock.CreateLoose<T>() - use
mock.Instanceas the runtime dependency - configure behavior with
Setup(...)/SetupSet(...) - match arguments with
Arg.* - verify through
CallsTo(...)+ standard assertions, withVerify(..., Times...)andVerifyNoOtherCalls()available when they help - order calls with
Mock.Sequence()/.InSequence(...)when sequencing matters - configure
ref/outbehavior withArg.Ref<T>.AnyplusSetsByRefParameter(index, value) - emit events with
mock.Event(name).Emit(...) - clear mutable state with
mock.Reset()
For low-friction migration, Burla also keeps a thin compatibility layer: .Object, It.*, and SetupGet(...).
The default analyzers surface those as BURLA010, BURLA011, and BURLA012, while BURLA020 fixes forgotten () on zero-argument Times factories inside Verify(...).
📖 Full documentation — Getting started, API guide, and migration guides.
If you're evaluating Burla from a Moq or NSubstitute codebase, start with the migration guides and the LLM migration reference before broad rewrites.
- NuGet package — Package page, install metadata, and release stream
- Getting Started — Install and write your first mock
- API Guide — Complete reference, including class mocking,
CallsTo(...), and optional verification helpers - Migrate from Moq — Side-by-side comparison
- Migrate from NSubstitute — Side-by-side comparison
- LLM Migration Reference — Self-contained prompt for automated migration
- Sample projects — Side-by-side Burla, Moq, and NSubstitute examples
Burla 1.0 covers the mocking workflows most .NET teams need in day-to-day test suites, with a focused API that stays easy to learn, easy to read in reviews, and practical to adopt in existing codebases.
- interfaces, abstract classes, and concrete classes with virtual members
- strict-by-default and loose mock behavior
- async methods and streams, sequences, events, and
ref/outwriteback - call inspection, ordered verification, and reset support
- compatibility aliases, analyzers, and migration guides for Moq or NSubstitute users
It focuses on the patterns most teams hit every day. One notable advanced case still out of scope for 1.0 is protected-member setup.
For maintainers, contributors, and curious evaluators, the design folder captures background rationale and focused design notes:
- design-goals.md - Core philosophy and strict-by-default rationale
- quirks.md - Pain points we're solving
- api-alternatives.md - Core API alternatives, rejected paths, and post-1.0 revisit list
- public-api-policy.md - Public API policy, native dialect, and compatibility rules
MIT - Free forever. No pranks here. 🤝