Burla — LLM Migration Reference¶
This is a self-contained reference for LLMs (or any automated tool) to convert .NET mocking code from Moq or NSubstitute to Burla. Paste this file into your system prompt or provide it as context.
This reference stays short enough to include next to the real test and production code, so the model can focus on the code under test instead of spending most of its context on mocking migration rules.
Namespace¶
Remove: using Moq;, using Moq.Protected;, using NSubstitute;, using NSubstitute.ExceptionExtensions;
Core types¶
| Type | Purpose |
|---|---|
Mock |
Static entry point. Mock.Of<T>() creates a mock wrapper; Mock.Create<T>() / Mock.CreateLoose<T>() return the runtime instance directly. |
IMock<T> |
Mock wrapper. Has .Instance (preferred), .Object (compatibility alias), .CallBase, .Setup(...), .SetupGet(...), .SetupSet(...), .CallsTo(...), .Verify(...), .Event(...).Emit(...), .VerifyNoOtherCalls(), .Reset(), .RecordedCalls. |
MockSequence |
Ordered verification helper created with Mock.Sequence() and used via .InSequence(sequence). |
Arg |
Argument matchers: Arg.Any<T>(), Arg.Is<T>(predicate), Arg.IsIn(...), Arg.IsNotIn(...), Arg.IsNull<T>(), Arg.IsNotNull<T>(), Arg.Ref<T>.Any. |
MockBehavior |
Strict (default, throws on unconfigured calls) or Loose (returns defaults). |
Times |
Never(), Once(), AtLeastOnce(), AtLeast(n), AtMost(n), Exactly(n), Between(from, to). |
CallRecord |
Recorded call: .Method, .Arguments, .ReturnValue, .Timestamp, .GetArgument<T>(index). |
UnexpectedCallException |
Thrown in strict mode for unconfigured calls. Includes a public ClosestMatches list of SetupInfo entries showing likely misconfigured setups ranked by relevance. |
VerificationException |
Thrown by Verify on count mismatch. |
SequenceExhaustedException |
Thrown when a return sequence is exhausted and no alternative exhaustion behavior was configured. |
Setup patterns¶
Class mocking (abstract and concrete classes)¶
// Abstract class
var mock = Mock.Of<MyAbstractService>();
mock.Setup(x => x.GetData()).Returns("mocked");
// Concrete class with virtual methods
var mock = Mock.Of<ConcreteService>();
mock.Setup(x => x.VirtualMethod()).Returns(42);
// With constructor arguments
var mock = Mock.Of<StorageBase>("connectionString", 30);
mock.Setup(x => x.Connect()).ReturnsAsync(true);
// With behavior and constructor arguments
var mock = Mock.Of<StorageBase>(MockBehavior.Loose, "connectionString", 30);
Method returning a value¶
var mock = Mock.Of<IService>();
mock.Setup(x => x.GetValue(Arg.Any<int>())).Returns(42);
mock.Setup(x => x.GetValue(Arg.Is<int>(n => n > 0))).Returns(999);
mock.Setup(x => x.GetValue(5)).Returns(100); // exact match
var result = mock.Instance.GetValue(5);
Void method¶
mock.Setup(x => x.DoSomething(Arg.Any<string>())); // allow call (strict mode)
mock.Setup(x => x.DoSomething(Arg.Any<string>())).Callback(() => {}); // with untyped callback
mock.Setup(x => x.DoSomething(Arg.Any<string>()))
.Callback<string>(msg => captured = msg); // typed callback
mock.Setup(x => x.DoSomething("bad")).Throws<InvalidOperationException>();
Typed callbacks¶
// Void method — typed callback captures arguments
mock.Setup(x => x.Send(Arg.Any<string>()))
.Callback<string>(msg => captured = msg);
mock.Setup(x => x.SendToUser(Arg.Any<string>(), Arg.Any<string>()))
.Callback<string, string>((userId, msg) => { });
// Return method — typed callback runs after value is produced
mock.Setup(x => x.Add(Arg.Any<int>(), Arg.Any<int>()))
.Returns(0)
.Callback<int, int>((a, b) => { capturedA = a; capturedB = b; });
Overloads: Callback<T1> through Callback<T1, T2, T3, T4>.
Typed Returns (argument forwarding)¶
mock.Setup(x => x.Add(Arg.Any<int>(), Arg.Any<int>()))
.Returns<int, int>((a, b) => a + b);
mock.Setup(x => x.GetDataAsync(Arg.Any<int>()))
.Returns<int>(id => Task.FromResult($"data-{id}"));
Overloads: Returns<T1> through Returns<T1, T2, T3, T4>.
Factory-based Throws¶
mock.Setup(x => x.Divide(Arg.Any<int>(), Arg.Any<int>()))
.Throws<int, int, InvalidOperationException>((a, b) =>
new InvalidOperationException($"Cannot divide {a} by {b}"));
Overloads: Throws<T1, TException> through Throws<T1, T2, T3, T4, TException>.
Property¶
mock.Setup(x => x.Name).Returns("test");
mock.SetupGet(x => x.Name).Returns("test"); // Moq-compatible alias
Sequence¶
mock.Setup(x => x.Next()).ReturnsSequence(1, 2, 3); // throws after exhaustion by default
mock.Setup(x => x.Next()).ReturnsSequence(1, 2).ThenReturns(0);
mock.Setup(x => x.Next()).ReturnsSequence(1, 2).ThenThrows<InvalidOperationException>();
Async¶
mock.Setup(x => x.GetAsync(1)).Returns("data"); // smart auto-wrap into Task<T>
mock.Setup(x => x.GetAsync(1)).ReturnsAsync("data"); // explicit (same)
mock.Setup(x => x.GetAsync(1)).Returns(Task.FromResult("data")); // fully explicit
mock.Setup(x => x.GetCountAsync()).Returns(42); // smart auto-wrap into ValueTask<T>
mock.Setup(x => x.GetCountAsync()).ReturnsAsync(42); // explicit (same)
IAsyncEnumerable¶
mock.Setup(x => x.StreamAsync(Arg.Any<CancellationToken>()))
.ReturnsAsyncEnumerable("a", "b", "c");
mock.Setup(x => x.StreamAsync(Arg.Any<CancellationToken>()))
.ReturnsAsyncEnumerable(async (yield, ct) =>
{
for (int i = 0; i < 5; i++)
{
ct.ThrowIfCancellationRequested();
await yield($"item-{i}");
}
});
mock.Setup(x => x.StreamAsync(Arg.Any<CancellationToken>()))
.ReturnsAsyncEnumerable("a", "b", "c")
.WithDelayBetweenItems(TimeSpan.FromMilliseconds(50));
Out parameters¶
Ref parameters¶
Events¶
// Subscribe to an event
mock.Instance.MessageReceived += (sender, msg) => { /* handle */ };
// Emit the event with Burla's native event API
mock.Event(nameof(IEventPublisher.MessageReceived)).Emit(mock.Instance, "Hello!");
// Emit an event with EventArgs (e.g., PropertyChangedEventArgs)
mock.Event(nameof(INotifyPropertyChanged.PropertyChanged)).Emit(mock.Instance, new System.ComponentModel.PropertyChangedEventArgs("PropertyName"));
mock.Event(name).Emit(...) is Burla's event API: it throws for unknown event names, is a no-op when the named event has no subscribers, and requires the exact handler argument count for the event delegate signature.
Verification patterns¶
Return value with callback¶
mock.Setup(x => x.GetValue(1)).Returns(42).Callback(() => callCount++);
mock.Setup(x => x.GetValue(Arg.Any<int>()))
.Returns(42)
.Callback<int>(id => lastId = id);
Arg matchers in helper methods¶
Arg matchers work from helper methods, not just directly in lambdas:
// This helper method works in Setup and CallsTo expressions
private static string IsNonEmpty() => Arg.Is<string>(s => !string.IsNullOrEmpty(s));
mock.Setup(x => x.Send(IsNonEmpty())).Callback(() => { });
var calls = mock.CallsTo(x => x.Send(IsNonEmpty()));
Verification patterns¶
// Query and assert (preferred for Burla-native tests)
Assert.Single(mock.CallsTo(x => x.Method()));
Assert.Empty(mock.CallsTo(x => x.Method()));
Assert.Equal(3, mock.CallsTo(x => x.Method(Arg.Any<int>())).Count);
// Verify (optional helper, mainly for low-diff Moq migrations or VerifyNoOtherCalls)
mock.Verify(x => x.Method(), Times.Once());
mock.Verify(x => x.Method(), Times.Never());
mock.Verify(x => x.Method(Arg.Any<int>()), Times.Exactly(3));
// Verify no other calls were made (calls must be verified via Verify first)
mock.Verify(x => x.Method(), Times.Once());
mock.VerifyNoOtherCalls();
// Ordered verification across one or more mocks
var otherMock = Mock.Of<IOtherService>();
using var sequence = Mock.Sequence();
mock.Setup(x => x.Step1()).InSequence(sequence);
otherMock.Setup(x => x.Step2()).InSequence(sequence);
mock.Instance.Step1();
otherMock.Instance.Step2();
// Out-of-order calls or unobserved steps throw VerificationException.
// Reset mutable state (setups, recorded calls, verification tracking, event subscriptions)
// The mock object itself and settings like CallBase are unchanged.
mock.Reset();
// Inspect recorded calls
var calls = mock.RecordedCalls;
var arg0 = calls[0].GetArgument<string>(0);
Moq → Burla translation rules¶
Apply these transformations in order:
- Namespace:
using Moq;→using Burla;. Removeusing Moq.Protected;. - Creation:
new Mock<T>()→Mock.Of<T>(MockBehavior.Loose).new Mock<T>(MockBehavior.Strict)→Mock.Of<T>(). Usemock.Instanceas the preferred runtime value;mock.Objectcan stay in low-diff Moq migrations. - Class mocking:
new Mock<AbstractClass>()→Mock.Of<AbstractClass>(MockBehavior.Loose).new Mock<ConcreteClass>(arg1, arg2)→Mock.Of<ConcreteClass>(MockBehavior.Loose, arg1, arg2). - Matchers: Prefer
Arg.Any<T>(),Arg.Is<T>(pred),Arg.IsIn(...),Arg.IsNotIn(...),Arg.IsNotNull<T>(), andArg.Ref<T>.Any. KeepingIt.*is also valid as low-cost Moq compatibility sugar. - Property getters:
mock.SetupGet(x => x.Prop)can stay asmock.SetupGet(x => x.Prop)or be normalized tomock.Setup(x => x.Prop). - Sequences:
mock.SetupSequence(x => ...).Returns(a).Returns(b)→mock.Setup(x => ...).ReturnsSequence(a, b). - Async:
mock.Setup(...).ThrowsAsync(ex)→mock.Setup(...).Throws(ex)(Burla auto-wraps).mock.Setup(...).ReturnsAsync(val)→mock.Setup(...).Returns(val)(smart auto-wrap) or keep.ReturnsAsync(val). - Verify:
mock.Verify(x => x.M(), Times.Once())→Assert.Single(mock.CallsTo(x => x.M()))(preferred) or keepmock.Verify(x => x.M(), Times.Once())for a low-diff Moq port. - Out params: Remove delegate types.
out It.Ref<T>.IsAny→out Arg.Ref<T>.Any, add.SetsByRefParameter(index, value). - Ref params: Same as out.
ref It.Ref<T>.IsAny→ref Arg.Ref<T>.Any, add.SetsByRefParameter(index, value). - Callbacks:
Callback<T1, T2>((a, b) => ...)→.Callback<T1, T2>((a, b) => ...)(typed callbacks are supported). - Invocations:
mock.Invocations→mock.RecordedCalls. - VerifyNoOtherCalls:
mock.VerifyNoOtherCalls()→mock.VerifyNoOtherCalls()(identical). - Reset:
mock.Reset()→mock.Reset().
NSubstitute → Burla translation rules¶
Apply these transformations in order:
- Namespace:
using NSubstitute;→using Burla;. Removeusing NSubstitute.ExceptionExtensions;. - Creation:
Substitute.For<T>()→ split intovar mock = Mock.Of<T>(MockBehavior.Loose);andvar sub = mock.Instance;. Replace all direct usage of the substitute variable withmock.Instance, or useMock.CreateLoose<T>()when you do not need the wrapper later. - Class creation:
Substitute.For<AbstractClass>()→var mock = Mock.Of<AbstractClass>(MockBehavior.Loose);.Substitute.For<ConcreteClass>(arg1, arg2)→var mock = Mock.Of<ConcreteClass>(MockBehavior.Loose, arg1, arg2);. - Setup:
sub.Method(args).Returns(val)→mock.Setup(x => x.Method(args)).Returns(val). - Matchers:
Arg.Any<T>(),Arg.Is<T>(pred)— same! AddArg.IsIn(...),Arg.IsNotIn(...),Arg.IsNull<T>(),Arg.IsNotNull<T>(),Arg.Ref<T>.Anyas needed. - Void methods:
sub.When(x => x.Method(args)).Do(...)→mock.Setup(x => x.Method(args)).Callback(...). - Throw on void:
sub.When(x => x.M()).Do(_ => throw new Ex())→mock.Setup(x => x.M()).Throws<Ex>(). - Exceptions:
sub.Method().Throws(ex)→mock.Setup(x => x.Method()).Throws(ex). - Sequences:
sub.Method().Returns(a, b, c)→mock.Setup(x => x.Method()).ReturnsSequence(a, b, c). - Verification:
sub.Received().Method()→Assert.Single(mock.CallsTo(x => x.Method())).sub.DidNotReceive().Method()→Assert.Empty(mock.CallsTo(x => x.Method())).sub.Received(n).Method()→Assert.Equal(n, mock.CallsTo(x => x.Method()).Count). - Call inspection:
sub.ReceivedCalls()→mock.RecordedCalls.call.GetArguments()[i]→call.GetArgument<T>(i). - Out params:
x[1] = value; return true;pattern →.Returns(true).SetsByRefParameter(1, value). Arg.Do<T>:Arg.Do<T>(callback)→.Callback<T>(callback)on the setup.ClearReceivedCalls:sub.ClearReceivedCalls()→mock.Reset()(note: also clears setups, verification tracking, and event subscriptions; it does not changeCallBase).
Important behavioral differences¶
- Strict by default: Burla throws
UnexpectedCallExceptionfor calls without a setup. Moq defaults to loose. NSubstitute is always loose. - Sequence exhaustion: Burla throws
SequenceExhaustedExceptionby default. Moq returnsdefault(T). NSubstitute repeats the last value. - Last-match-wins: When multiple setups match, the last one configured wins. Same as Moq.
- No class mocking for sealed classes: Burla can mock interfaces, abstract classes, and concrete classes with virtual methods, but sealed classes cannot be mocked.
- Non-virtual methods are not intercepted: on concrete classes, non-virtual methods run the original implementation.
- Event emission:
mock.Event(nameof(SomeType.EventName)).Emit(sender, args...)is the public API. Unknown names throw, unsubscribed known events are ignored, and argument counts must match exactly. - Arg matchers in helpers:
Arg.Any<T>(),Arg.Is<T>(...), etc. work when called from helper methods outside the lambda expression tree. This is useful for creating reusable matcher helpers. - Preferred everyday spelling: Burla-native docs prefer
.Instance,Arg,Setup(...),SetsByRefParameter(...),Event(...).Emit(...), andCallsTo(...)+ standard assertions for verification..Verify(..., Times...),.Object,It, andSetupGet(...)remain available as compatibility sugar for migrations.