Migrating from NSubstitute¶
Side-by-side comparison of NSubstitute and Burla patterns. Every example shows the NSubstitute code you have today and the Burla equivalent.
Package change¶
- <PackageReference Include="NSubstitute" Version="..." />
+ <PackageReference Include="Burla" Version="..." />
Creating mocks¶
Key difference: wrapper object
NSubstitute returns the mock directly. Burla returns a wrapper (IMock<T>) — use .Instance to get the runtime value (.Object remains as a Moq compatibility alias).
The wrapper holds setup and call-recording state.
If you only need the runtime dependency and will not verify through the wrapper later, Mock.CreateLoose<T>() is often the closest Burla convenience helper:
Strict by default
NSubstitute has no strict mode — all mocks always return defaults for unconfigured calls.
Burla defaults to strict (throws on unconfigured calls). Use Mock.Of<T>(MockBehavior.Loose) for NSubstitute-like behavior.
Setup and returns¶
NSubstitute uses the fluent style directly on the substitute. Burla uses .Setup(x => ...) on the mock wrapper.
Argument matchers¶
| NSubstitute | Burla |
|---|---|
Arg.Any<int>() |
Arg.Any<int>() |
Arg.Is<int>(n => n > 0) |
Arg.Is<int>(n => n > 0) |
Arg.Is("hello") |
"hello" (just pass the value) |
The Arg class is very similar! Burla also adds Arg.IsIn(...), Arg.IsNotIn(...), Arg.IsNull<T>(), and Arg.IsNotNull<T>().
Void methods¶
Burla uses the same .Setup(x => ...) pattern for void methods. No separate .When(...).Do(...) syntax.
Arg.Do<T> equivalent
NSubstitute's Arg.Do<T>(callback) has no direct equivalent. Use typed Callback<T> instead:
Exceptions¶
Properties¶
Sequences¶
NSubstitute repeats the last value by default. Burla throws an exception by default. Use .ThenRepeatsLast() to match NSubstitute's behavior, or customize via .ThenReturns(value).
Verification¶
No Received() syntax
NSubstitute's .Received().Method() pattern doesn't exist in Burla. Burla-native docs use CallsTo(...) + standard assertions.
Verify(..., Times...) still exists, but it is mainly there for Moq-style migrations and VerifyNoOtherCalls().
Async methods¶
Smart async returns
Like NSubstitute, Burla auto-wraps plain values into Task<T> or ValueTask<T>. ReturnsAsync is also available if you prefer being explicit.
IAsyncEnumerable¶
Ref/Out parameters¶
Call inspection¶
Events¶
// Subscribe
eventPublisher.MessageReceived += (sender, msg) => { /* handle */ };
// Raise with event args
eventPublisher.Raise(eventPublisher.MessageReceived += null, new CustomEventArgs("hello"));
// Raise simple EventArgs
eventPublisher.Raise(eventPublisher.MessageReceived += null, EventArgs.Empty);
// Subscribe (same pattern)
mock.Instance.MessageReceived += (sender, msg) => { /* handle */ };
// Emit with Burla's native event API
mock.Event(nameof(IEventPublisher.MessageReceived)).Emit(mock.Instance, "hello");
// For EventHandler<TEventArgs>:
mock.Event(nameof(INotifyPropertyChanged.PropertyChanged)).Emit(mock.Instance, new System.ComponentModel.PropertyChangedEventArgs("PropertyName"));
Burla's event API is mock.Event(name).Emit(...). Pass the event name and then the arguments that would be passed to the event handler (typically sender first, then event data).
Event handler signature matching
The arguments passed to Emit must match the event handler signature. For EventHandler<T>, pass (sender, eventArgs). For custom handlers like Action<T>, pass just the data parameter(s).
Clearing calls (ClearReceivedCalls → Reset)¶
Reset clears everything
NSubstitute's ClearReceivedCalls() only clears recorded calls. Burla's Reset() also clears setups, verification tracking, and event subscriptions. It does not recreate the mock object or change settings like CallBase.
Class mocking¶
// Abstract class
var mock = Mock.Of<MyAbstractService>(MockBehavior.Loose);
mock.Setup(x => x.GetData()).Returns("mocked");
var service = mock.Instance;
// Concrete class with constructor args
var mock = Mock.Of<ConcreteRepository>(MockBehavior.Loose, "connStr", 30);
mock.Setup(x => x.VirtualMethod()).Returns(99);
var repo = mock.Instance;
Strict by default
NSubstitute class substitutes always return defaults. Burla defaults to strict, so add MockBehavior.Loose when migrating.
Quick reference¶
| NSubstitute | Burla |
|---|---|
Substitute.For<T>() |
Mock.CreateLoose<T>() (setup-only) or Mock.Of<T>(MockBehavior.Loose) + .Instance |
sub.Method().Returns(val) |
mock.Setup(x => x.Method()).Returns(val) |
Arg.Any<T>() |
Arg.Any<T>() |
Arg.Is<T>(pred) |
Arg.Is<T>(pred) |
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) |
sub.ReceivedCalls() |
mock.RecordedCalls |
.Returns(a, b, c) |
.ReturnsSequence(a, b, c) |
.When(x => ...).Do(...) |
.Setup(x => ...).Callback(...) |
.When(x => ...).Throw(...) |
.Setup(x => ...).Throws(...) |
Arg.Do<T>(callback) |
.Callback<T>(callback) (on the setup) |
sub.ClearReceivedCalls() |
mock.Reset() |
Substitute.For<AbstractClass>() |
Mock.Of<AbstractClass>(MockBehavior.Loose) + .Instance |
Substitute.For<Class>(args) |
Mock.Of<Class>(MockBehavior.Loose, args) + .Instance or Mock.CreateLoose<Class>(constructorArgs: args) |
| No strict mode | Strict by default, MockBehavior.Loose opt-in |