Ryan Leach
Ryan Leach

Reputation: 4470

NSubstitute out arrays, with ambiguous parameters?

NSubstitute is complaining that my arguments are ambiguous, however as far as I'm aware they are fully spec'd. I'd add more details but I've already boiled it down to this small example. (Edit: now even smaller, removed out parameter, but not the definition for the argument.)

The end goal I had was for 'inlined method' to be a helper method for the tests, having an input of the result, and the expected ITextObjC[] which represents an array of errors.

Given the minimal, complete, Verifiable example:

    public interface test
    {
        bool testMethod(
            bool boolA,
            bool boolB);
    }

    public interface ITestObjC { }

    public class TestObjC : ITestObjC { }

    [Test]
    public void SillyTest2()
    {
        var fakeTest = Substitute.For<test>();

        fakeTest.testMethod(  false, false);

        ITestObjC[] recOutArr = Arg.Is<ITestObjC[]>(x => x == null);

        fakeTest.Received(1).testMethod(
            Arg.Is<bool>(false),
            Arg.Is<bool>(false));
    }

Results in:

NSubstitute.Exceptions.AmbiguousArgumentsException : Cannot determine argument specifications to use.
Please use specifications for all arguments of the same type.
   at NSubstitute.Core.Arguments.NonParamsArgumentSpecificationFactory.Create(Object argument, IParameterInfo parameterInfo, ISuppliedArgumentSpecifications suppliedArgumentSpecifications)
   at NSubstitute.Core.Arguments.ArgumentSpecificationFactory.Create(Object argument, IParameterInfo parameterInfo, ISuppliedArgumentSpecifications suppliedArgumentSpecifications)
   at NSubstitute.Core.Arguments.MixedArgumentSpecificationsFactory.<>c__DisplayClass3_0.<Create>b__0(Object argument, Int32 i)
   at System.Linq.Enumerable.<SelectIterator>d__5`2.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at NSubstitute.Core.Arguments.MixedArgumentSpecificationsFactory.Create(IList`1 argumentSpecs, Object[] arguments, IParameterInfo[] parameterInfos)
   at NSubstitute.Core.Arguments.ArgumentSpecificationsFactory.Create(IList`1 argumentSpecs, Object[] arguments, IParameterInfo[] parameterInfos, MatchArgs matchArgs)
   at NSubstitute.Core.CallSpecificationFactory.CreateFrom(ICall call, MatchArgs matchArgs)
   at NSubstitute.Routing.Handlers.CheckReceivedCallsHandler.Handle(ICall call)
   at NSubstitute.Routing.Route.<>c__DisplayClass8_0.<Handle>b__0(ICallHandler x)
   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.Core.CallRouter.Route(ICall call)
   at NSubstitute.Proxies.CastleDynamicProxy.CastleForwardingInterceptor.Intercept(IInvocation invocation)
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Castle.Proxies.testProxy.testMethod(ITestObjA motionEnvelope, ITestObjB motionSeries, Boolean primaryLimits, Boolean testPitch, ITestObjC[]& exceedences)
   at HeliSAFE.DataStorage.Tests.SholMonitor.CommonSholMonitorTests.SillyTest2() in D:\Repositories\GitSAFE_Repos\helisafe.container\helisafe\HeliSAFE.DataStorage.Tests\SholMonitor\CommonSholMonitorTests.cs:line 375

on this line:

fakeTest.Received(1).testMethod(

Upvotes: 1

Views: 1837

Answers (2)

David Tchepak
David Tchepak

Reputation: 10484

The short answer is don't use argument matchers outside of a Received or Returns.

The longer answer is that to get NSubstitute's syntax it does some questionable things. In this case, every time you do Arg.Is or Arg.Any it pushes the argument matcher into a static (threadlocal) queue. When it receives an actual call it then retrieves these argument matchers to work out what calls match (for Received) or what calls to stub (for Returns).

In this case three argument matchers are queued, but the fakeTest .Received().testMethod(bool a, bool b) takes just two, so NSubstitute is not sure where the three argument matchers are meant to go.

As an aside, the detection of these cases and error messages are set to improve with the next version of NSubstitute (after 3.1).

Upvotes: 4

Ryan Leach
Ryan Leach

Reputation: 4470

NSubstitute appears to have some sort of completeness check that runs when evaluating Received calls that contain Arg.Is.

Leaving out the Arg.Is in a Received call, or not calling .Received, or commenting out the Orphan argument appears to fix it, but I don't know why.

Upvotes: 0

Related Questions