I've been a big fan of Rhino.Mocks for many years, but the original Rhino.Mocks maintainer (Oren Eini aka Ayende) stated in 2013 that he is no longer maintaining the project and has handed the project over to a new maintainer (Mike Meisinger), but Mike has not been actively maintaining the project. It's effectively dead and very unlikely to support future versions of .NET, including .NET core.
A while back I wrote a Quick Guide to Using Rhino.Mocks and in last week's post, I gave an overview of Moq for Rhino.Mocks Users. While Moq seems to be the current front runner as a Rhino.Mocks replacement, there's another player in town with NSubstitute. So in the same vane as my Moq post, I'm providing a guide to help people make the transition (or at least help with a review) from Rhino.Mocks to NSubstitue.
The format of this post will follow that of the others to help with cross-referencing between them.
Overall, I'm not a big fan of NSubstitute's syntax, as it looks too similar to just calls to the methods themselves, which:
- makes it harder to understand, as the reader must know which calls are setting up stubs and which are real calls.
- makes it much more likely you'll accidentally do the wrong thing and call a real method.
Now, if you're only mocking interfaces, then this wouldn't be an issue -- but rarely do I find a codebase that allows everything to be an interface.
Generating Different Mock Types
By default, NSubstitue's .For<T>
method generates something close to a Dynamic mock -- that is, if you don't explicitly provide a return value, it will return the default value for the data type of the return value if it's a value type (0 for numbers, false for bools, empty string for string), but for object types, it's a bit more complicated. From their documentation:
...any properties or methods that return an interface, delegate, or purely virtual class* will automatically return substitutes themselves.
A pure virtual class is defined as one with all its public methods and properties defined as virtual or abstract and with a default, parameterless constructor defined as public or protected.
So it won't return null in those cases. Instead, it creates a new mock of the return type. Otherwise, it will return null.
Be careful, thought -- if you are using a real class (not an interface), it will call the underlying methods if they aren't virtual.
That said, there is the concept of a partial mock using .ForPartsOf<T>
-- that is, a mock that can use the underlying object's implementation. However, to prevent calling the real methods for the methods you do want to mock, you must use the syntax described in the Advanced Argument Constraints section below.
Rhino.Mocks | NSubstitute | |
---|---|---|
Dynamic-ish Mock | IFoo mock = MockRepository.GenerateMock<IFoo>(); | IFoo substitute = Substitute.For<IFoo>(); |
Partial Mock | IFoo mock = MockRepository.GeneratePartialMock<IFoo>(); | IFoo substitute = Substitue.ForPartsOf<IFoo>(); |
There isn't an option to create a Strict mock in NSubstitute, and it looks like there won't ever be one.
Passing Constructor Arguments
If you need to pass arguments to the constructor of the class you're trying to mock, there are overloads to allow you to do that.
Rhino.Mocks | NSubstitute |
---|---|
IFoo mock = MockRepository.GenerateMock<SomeClass>(param1, param2); | Substitue.ForPartsOf<SomeClass>()(param1, param2); |
Stubs vs Mocks (or not)
The syntax for NSubstitute is a little different than the others. In most cases, there's not an explicit method you call to create the mock/stub -- rather, you basically call the method you want to create a substitue for. Also, there's no distinction between a mock and a stub -- they're all just substitutions. But since they don't create _expectations_, I would classify them as stubs.
You use the .Returns()
method to setup the stub. Note that you can provide multiple values to .Returns()
which will set up a chain of calls, like this: .Returns(valueForFirstCall, valueForSecondCall, valueForThirdCall)
. This works for methods and properties.
For Methods:
Rhino.Mocks | NSubstitute | |
---|---|---|
Stub | mock.Stub(x => x.SomeMethod()).Return(true); | substitute.SomeMethod().Returns(true); |
Mock | mock.Expect(x => x.SomeMethod()).Return(true); | (not supported) |
For Properties:
Rhino.Mocks | NSubstitute | |
---|---|---|
Stub | mock.Stub(x => x.SomeProperty).Return(true); | substitute.SomeProperty.Returns(true); or substitute.SomeProperty = true; |
Mock | mock.Expect(x => x.SomeProperty).Return(true); | (not supported) |
Unlike Rhino.Mocks, however, if some other code sets the property value to something else, NSubstitute's stub will return the new value, not the value you stipulated in your stub. In other words, NSubstitue's properties will act like regular properties, and your stub just sets an initial value.
Verifying expectations
Since you're not creating expectations with NSubstitute, there are no mass validation options. Instead, you need to check each stub (which, being more explicit, is probably the better route anyway).
For Methods:
Rhino.Mocks | NSubstitute | |
---|---|---|
Called | mock.AssertWasCalled(x => x.SomeMethod()); | substitute.Received().SomeMethod(); |
Called a specific number of times | mock.AssertWasCalled(x => x.SomeMethod(), options => options.Repeat.Times(2) ); | substitute.Received(2).SomeMethod(); |
Not called | mock.AssertWasNotCalled(x => x.SomeMethod()); | substitute.DidNotReceive().SomeMethod(); or substitute.DidNotReceiveWithAnyArgs().SomeMethod(); |
For Properties:
Rhino.Mocks | NSubstitute | |
---|---|---|
Get | mock.AssertWasCalled(x => x.SomeProperty); | var temp = substitue.Received().SomeProperty; |
Set | mock.AssertWasCalled(x => x.SomeProperty = true); | substitue.Received().SomeProperty = true; |
Not called | mock.AssertWasNotCalled(x => x.SomeProperty = true); | substitue.DidNotReceive().SomeProperty = true; or substitue.DidNotReceiveWithAnyArgs().SomeProperty = true; |
Note that for the getter, you must set a variable to the return value to prevent a compiler error.
The WithAnyArgs
versions will ignore whatever parameters (for methods) or set values (for properties) you use in your check and will verify against any inputs.
Advanced Argument Constraints
Both frameworks provide ways to put advanced constraints on the arguments that trigger a mock. Below are examples -- you'll need to consult the framework documentation for the full list of available constraints.
Rhino.Mocks
mock.Stub(dao => dao.GetRecordFromDatabase(
Arg<int>.Is.GreaterThanOrEqual(0),
Arg<decimal>.Is.NotEqual(2.0),
Arg<List<string>>.List.ContainsAll(new List<string> { "foo", "bar" }),
Arg<object>.Is.NotNull,
Arg<object>.Is.Anything))
.Return(recordFromDatabase);
NSubstitute
substitute.GetRecordFromDatabase(
Arg.Is<int>(i => i >= 0),
Arg.Is<decimal>(d => d != 2.0m),
Arg.Do<int>(x => capturedValue = x ),
Arg.Any<object>()))
.Returns(recordFromDatabase);
Or, to ignore the arguments altogether, use .ReturnsForAnyArgs()
. This is similar to Rhino.Mocks' .IgnoreArguments()
method.
Providing a Method Implementation / Using the Input Params
For Rhino.Mocks, in order to provide an alternate implementation, you use the .Do()
method to provide a delegate. In NSubstitue, you provide a delegate to the .Returns()
call.
Rhino.Mocks
mock.Stub(dao => dao.GetRecordFromDatabase(0))
.IgnoreArguments()
.Repeat.Any()
.Do((Func<int, ImportantData>)(input => new ImportantData
{
Name = "Orignal Name",
RecordId = input
}));
NSubstitute
substitute.GetRecordFromDatabase(0)
.ReturnsForAnyArgs(input => new ImportantData
{
Name = "Orignal Name",
RecordId = input.ArgAt<int>(0)
});
Throwing an Exception Instead
If the return type of the method is not void
, you just provide a delegate to .Returns()
that throws an exception. However, if the return type is void
, then you use a .When().Do()
syntax instead:
Rhino.Mocks | NSubstitute |
---|---|
mock.Stub(x => x.SomeMethod()).Throw(new Exception("POW!")); | substitute.SomeMethod().Returns(x => { throw new Exception("POW!"); }); or substitute.When(x => x.VoidMethod()).Do(x => { throw new Exception("POW!"); }); |
Testing Non-Public Members
With Rhino.Mocks, you can’t mock private or internal members, but you can mock internal members if you add an InternalsVisibleTo
attribute for the Castle dynamic proxy assembly. NSubstitute also uses the same proxy, so you'll still need to add the attribute. See the Moq Quickstart Guide for details on how to do this.