Migrating from Moq¶
Side-by-side comparison of Moq and Burla patterns. Every example shows the Moq code you have today and the Burla equivalent.
Package change¶
- <PackageReference Include="Moq" Version="..." />
+ <PackageReference Include="Burla" Version="..." />
Creating mocks¶
Default behavior change
Moq defaults to loose (unconfigured calls return default).
Burla defaults to strict (unconfigured calls throw).
If you're migrating a large codebase that relies on loose behavior, pass MockBehavior.Loose explicitly.
Getting the mock instance¶
Burla keeps .Object as a compatibility alias, so many Moq tests can keep this spelling unchanged during migration. In Burla-native docs and new examples you will usually see .Instance instead.
Quick fixes are IDE-only and optional
The default Burla package includes the BURLA01x compatibility diagnostics for .Object to .Instance, It.* to Arg.*, and SetupGet(...) to Setup(...), plus BURLA020 for forgotten zero-argument Times parentheses inside Verify(...).
In supported IDEs these show up as gentle info diagnostics and code fixes, and they do not block compilation.
If you want a quieter migration while you are still porting a large Moq codebase, lower the compatibility rules in .editorconfig:
dotnet_diagnostic.BURLA010.severity = silent
dotnet_diagnostic.BURLA011.severity = silent
dotnet_diagnostic.BURLA012.severity = silent
Use none instead if you want them fully off during migration, then restore them to info later if you want IDE nudges toward the native Burla spellings.
If you want the runtime without those suggestions, install Burla.Core instead. If you want to keep Burla but turn the suggestions off, suppress the Burla diagnostic IDs in .editorconfig:
Simple setup and returns¶
Identical syntax!
Argument matchers¶
| Moq | Burla |
|---|---|
It.IsAny<int>() |
It.IsAny<int>() (compat) / Arg.Any<int>() (native) |
It.Is<int>(n => n > 0) |
It.Is<int>(n => n > 0) (compat) / Arg.Is<int>(n => n > 0) |
It.IsIn("a", "b") |
It.IsIn("a", "b") (compat) / Arg.IsIn("a", "b") |
It.IsNotIn("a", "b") |
It.IsNotIn("a", "b") (compat) / Arg.IsNotIn("a", "b") |
It.IsNotNull<string>() |
It.IsNotNull<string>() (compat) / Arg.IsNotNull<string>() |
It.Ref<int>.IsAny |
It.Ref<int>.IsAny (compat) / Arg.Ref<int>.Any |
Burla-native docs use Arg, but It is available as compatibility sugar when you want a Moq migration to stay low-diff.
Void methods¶
Typed callback overloads (Callback<T1> through Callback<T1,T2,T3,T4>) work the same way as Moq.
Exceptions¶
Identical syntax.
Properties¶
Identical.
For low-diff Moq migrations, Burla also accepts SetupGet(...) as a compatibility alias for getter setup:
SetupAllProperties is not available in Burla
Moq's SetupAllProperties() auto-tracks property changes. In Burla, set up each property individually.
Property setters (SetupSet)¶
Burla's SetupSet(...) targets the property, not an assignment expression. It allows any assigned value by default and is the supported way to permit setter calls in strict mode.
Sequences¶
Exhaustion behavior differs
Moq returns default(T) after the sequence is exhausted. Burla throws an exception by default.
Use .ThenReturns(defaultValue) to match Moq's behavior explicitly, or .ThenRepeatsLast() if you want repeat-last semantics instead.
Verification¶
// Option A: query and assert (recommended)
Assert.Single(mock.CallsTo(x => x.Send("test")));
Assert.Empty(mock.CallsTo(x => x.Send(Arg.Any<string>())));
Assert.Equal(3, mock.CallsTo(x => x.Send(Arg.Any<string>())).Count);
// Option B: low-diff migration helper (throws on mismatch, like Moq)
mock.Verify(x => x.Send("test"), Times.Once());
mock.Verify(x => x.Send(Arg.Any<string>()), Times.Never());
mock.Verify(x => x.Send(Arg.Any<string>()), Times.Exactly(3));
If you keep low-diff Verify(...) calls during migration, the Times API is the same: Never(), Once(), AtLeastOnce(), AtLeast(n), AtMost(n), Exactly(n), Between(from, to). Once you are comfortable with Burla, most new code can stop at CallsTo(...) + standard assertions.
VerifyNoOtherCalls¶
Identical syntax! Both throw if unverified calls exist.
Note
As in Burla's other docs, only Verify(...) marks calls as verified for VerifyNoOtherCalls(). CallsTo(...) is query-only.
Verifiable() / VerifyAll()¶
Burla intentionally keeps verification explicit. Translate Moq's aggregate verification pattern into normal assertions in the Assert phase.
Async methods¶
Burla's .Returns(value) auto-wraps into Task.FromResult or ValueTask when the method is async. ReturnsAsync also works if you prefer being explicit.
IAsyncEnumerable¶
Ref/Out parameters¶
// Verbose: requires a delegate
mock.Setup(x => x.TryParse("42", out It.Ref<int>.IsAny))
.Returns(new TryParseDelegate((string _, out int result) =>
{
result = 42;
return true;
}));
delegate bool TryParseDelegate(string input, out int result);
// Ref: also needs a delegate
mock.Setup(x => x.Transform(ref It.Ref<string>.IsAny))
.Callback(new TransformDelegate((ref string value) =>
{
value = value.ToUpper();
}));
delegate void TransformDelegate(ref string value);
Callback after return¶
Identical syntax — typed Callback<T1..T4> overloads work the same way.
Call inspection¶
Class mocking¶
Use Mock.OfLoose<T>() helper
For class mock migration, use Mock.OfLoose<T>() as a shorthand for Mock.Of<T>(MockBehavior.Loose). This makes the migration from Moq's default loose behavior more concise.
Behavior difference
Moq defaults to loose mode for class mocks. Burla defaults to strict.
Add MockBehavior.Loose explicitly when migrating class mocks that rely on default values.
Partial mocks (CallBase)¶
Burla's CallBase is also opt-in, but it only affects unmatched non-abstract virtual members on class mocks. Explicit setups still win. Interface mocks, abstract members, and non-virtual members do not gain fallback behavior from CallBase.
Protected members¶
If your Moq tests depend on Moq.Protected, keep that part of the test as-is for now or refactor toward public/virtual seams before migrating. Protected-member setup and verification are intentionally unsupported in Burla 1.0.0.
Events (Event(...).Emit(...))¶
Burla's event API is mock.Event(name).Emit(...). Unknown event names throw, known events without subscribers are ignored, and Burla supports any event delegate arity as long as the supplied arguments match the handler signature.
Quick reference¶
| Moq | Burla |
|---|---|
new Mock<T>() |
Mock.Of<T>() |
new Mock<T>(MockBehavior.Strict) |
Mock.Of<T>() (default) |
new Mock<T>(MockBehavior.Loose) |
Mock.Of<T>(MockBehavior.Loose) |
mock.Object |
mock.Object (compatibility alias; new Burla docs prefer .Instance) |
It.IsAny<T>() |
It.IsAny<T>() (compatibility alias) or Arg.Any<T>() |
It.Is<T>(...) |
It.Is<T>(...) (compatibility alias) or Arg.Is<T>(...) |
It.IsIn(...) |
It.IsIn(...) (compatibility alias) or Arg.IsIn(...) |
It.Ref<T>.IsAny |
It.Ref<T>.IsAny (compatibility alias) or Arg.Ref<T>.Any |
.SetupGet(x => x.Property) |
.SetupGet(x => x.Property) (compatibility alias) or .Setup(x => x.Property) |
.SetupSet(x => x.Property = It.IsAny<T>()) |
.SetupSet<T>(x => x.Property) |
.SetupSequence().Returns().Returns() |
.ReturnsSequence(a, b) |
sequence exhaustion returns default(T) |
sequence exhaustion throws SequenceExhaustedException by default |
.ReturnsAsync(value) |
.ReturnsAsync(value) |
.ThrowsAsync(ex) |
.Throws(ex) (auto-wraps async) |
.Verify(expr, Times.Once()) |
Assert.Single(mock.CallsTo(...)) (preferred) or keep .Verify(expr, Times.Once()) for a low-diff port |
.Verifiable() / .VerifyAll() |
CallsTo(...) assertions or explicit .Verify(...) |
.VerifyNoOtherCalls() |
.VerifyNoOtherCalls() |
.Invocations |
.RecordedCalls |
.CallBase = true |
.CallBase = true |
.Raise(x => x.Event += null, ...) |
.Event("EventName").Emit(...) |
mock.Protected() |
unsupported / deferred in 1.0.0 |
.Reset() |
.Reset() |
.Callback<T1, T2>((a, b) => ...) |
.Callback<T1, T2>((a, b) => ...) |
new Mock<AbstractClass>() |
Mock.Of<AbstractClass>(MockBehavior.Loose) |
new Mock<Class>(arg1) |
Mock.Of<Class>(MockBehavior.Loose, arg1) |