NSubstitute
NSubstitute copied to clipboard
How to override the default behavior for unconfigured methods
I'm using NSubstitute (in conjunction with AutoFixture) to auto-mock service interfaces. Consider the following example
interface ISomeDependency
{
object MethodA();
object MethodB();
object MethodC();
}
class SomeClass
{
public SomeClass(ISomeDependency dependency) { /* ... */}
public object DoSomething()
{
return _dependency.MethodA(); // uses only MethodA
}
}
// in test
var dep = Fixture.Freeze<ISomeDependency>();
dep.MethodA().Returns(new object());
var sut = Fixture.Create<SomeClass>();
var result = sut.DoSomething();
As you can see the SUT only uses one method of the dependency interface. In this scenario I would like to ensure that all methods on the dependency substitute are either
- explicitly considered/configured by the test author
- never called by the sut
I see two approaches to this: Either I configure all other methods on the substitute to throw an exception or I assert that all other have not been called. The problem with both of those is that I have to do this explicitly for each of the other methods. This means that the test has to be adapted whenever the dependency is extended by an other method. A task which is all to easy ily overlooked.
As such the default NSubstitute behavior of silently returning null for any not configured method makes little sense. I would rather have it throw a NotImplemented exception so that I can quickly see when I have forgotten to configure a method. Is there a way to do this?
Alternatively I would welcome a variant of .ReturnsForAll<T>() that is not bound to a specific return type. More like a .DoThisForAllOther(Func<ICall> handler).
A third option would be a .DidNotReceiveAnyOtherCallWithAnyArgs() assert.
Hi @penenkel ,
I think the ReceivedCalls extension can be adapted to do what you want:
var allCalls = dep.ReceivedCalls();
foreach (var call in allCalls) {
Console.WriteLine(call.GetMethodInfo());
}
You could look at injecting an auto-value provider in to throw if not stubbed, but I think it would be easiest and most consistent to implement a method over ReceivedCalls, so ending up with something like !dep.ReceivedCalls().Where(call => call != allowedCalls).Any() (or a ReceivedOnly method that contains a call like that).