Skip to content

Instantly share code, notes, and snippets.

@patriksvensson
Last active August 28, 2016 11:41
Show Gist options
  • Save patriksvensson/7f02c47d699a9bfff1dcf7018b237272 to your computer and use it in GitHub Desktop.
Save patriksvensson/7f02c47d699a9bfff1dcf7018b237272 to your computer and use it in GitHub Desktop.
NSubstitute problem: How do I verify the call to IBuilder.Register(Action<IContainer>)?
public class BuilderExtensionsTests
{
public class TheRegisterFooMethod
{
[Fact]
public void Should_Register_Foo_With_Container()
{
// Given
var builder = Substitute.For<IBuilder>();
// When
builder.RegisterFoo();
// Then
builder.Received(1).Register(Arg.Is<Action<IContainer>>(container =>
{
// Not sure how to verify the call to Action<IContainer> here.
// This is obviously wrong...
container.RegisterType<Foo>();
}));
}
}
}
public static class BuilderExtensions
{
public static void RegisterFoo(this IBuilder builder)
{
builder.Register(container => container.RegisterType<Foo>());
}
}
public interface IBuilder
{
void Register(Action<IContainer> action);
}
public interface IContainer
{
void RegisterType<T>();
}
NSubstitute.Exceptions.ReceivedCallsException
Expected to receive exactly 1 call matching:
Register(Action<IContainer>)
Actually received no matching calls.
Received 1 non-matching call (non-matching arguments indicated with '*' characters):
Register(*Action<IContainer>*)
at NSubstitute.Core.ReceivedCallsExceptionThrower.Throw(ICallSpecification callSpecification, IEnumerable`1 matchingCalls, IEnumerable`1 nonMatchingCalls, Quantity requiredQuantity)
at NSubstitute.Routing.Handlers.CheckReceivedCallsHandler.Handle(ICall call)
at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)
at NSubstitute.Routing.Route.Handle(ICall call)
at NSubstitute.Proxies.CastleDynamicProxy.CastleForwardingInterceptor.Intercept(IInvocation invocation)
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at ClassLibrary1.BuilderExtensionsTests.TheRegisterFooMethod.Should_Register_Foo_With_Container() in C:\Source\Local\ClassLibrary1\BuilderExtensionsTests.cs:line 21
@dtchepak
Copy link

The reason for the test failure is that NSubstitute generally compares arguments by reference, so unless you have a reference to the precise Action<IContainer> instance this type of assertion won't work.

There are a few ways to approach testing this. I would probably do something like this:

        [Fact]
        public void Should_Register_Foo_With_Container()
        {
            // Given
            var container = Substitute.For<IContainer>();
            var builder = Substitute.For<IBuilder>();
            builder.Register(Arg.Invoke(container)); // stubs this call to invoke the Action<IContainer> with the given container

            // When
            builder.RegisterFoo();

            // Then
            container.Received().RegisterType<Foo>();
        }

Whenever builder.Register is called, NSubstitute will invoke the Action<IContainer> argument with the given substitute container. We then check that when builder.RegisterFoo() is called it will be passed an action that will RegisterType<Foo> on any container it is given. This checks that builder.Register was called (tested implicitly) with an action that works as expected (tested explicitly).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment