NSubstitute - TestFixture 1在TestFixture 2中导致AmbiguousArgumentsException

Tar*_*nam 10 c# nunit nsubstitute

我正在使用NUnit和NSubstitute编写C#单元测试.我正在测试一个类,它将尝试从实现以下接口的配置提供程序中检索对象:

public interface IConfigProvider<T> {
    T GetConfig(int id);
    T GetConfig(string id);
}
Run Code Online (Sandbox Code Playgroud)

正在测试的类只GetConfig在setUpFixture中使用int版本,我执行以下操作来设置一个总是返回相同虚拟对象的模拟配置提供程序:

IConfigProvider<ConfigType> configProvider = Substitute.For<IConfigProvider<ConfigType>>();
configProvider.GetConfig(Arg.Any<int>()).Returns<ConfigType>(new ConfigType(/* args */);
Run Code Online (Sandbox Code Playgroud)

如果TestFixture是唯一运行的TestFixture,则运行绝对正常.但是,在同一个程序集中的不同TestFixture中,我检查接收到的调用如下:

connection.Received(1).SetCallbacks(Arg.Any<Action<Message>>(), Arg.Any<Action<long>>(), Arg.Any<Action<long, Exception>>());
Run Code Online (Sandbox Code Playgroud)

如果这些Received测试在配置提供程序测试之前运行,则配置测试在SetUpFixture中失败并出现AmbiguousArgumentsException:

Here.Be.Namespace.ProfileManagerTests+Setup (TestFixtureSetUp):
SetUp : 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 System.Linq.Enumerable.<SelectIterator>d__7`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.RecordCallSpecificationHandler.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 Castle.Proxies.IConfigProvider`1Proxy.GetConfig(Int32 id)
at Here.Be.Namespace.ProfileManagerTests.Setup.DoSetup()
Run Code Online (Sandbox Code Playgroud)

令我感到困惑的是,即使在测试运行之间我也能观察到这种效果 - 如果我使用NUnit GUI Received单独运行测试,然后单独运行配置测试,配置测试将失败.如果我再次立即运行配置测试,它们将通过.

我试过的事情:

  • 如果configProvider.GetConfig(Arg.Any<string>()).Returns...重载是问题,也可以添加.
  • 我已经阅读了关于参数匹配NSubstitute文档,但我找不到解决方案.如果是必须为方法的int和字符串版本提供参数匹配器的情况,我无法弄清楚如何做到这一点.

碰巧,我正在使用的测试只会调用GetConfig值为0或1的方法,所以我只能Returns为这两个值提供规范而根本不使用匹配,但我想了解如何解决这个问题通常.

Dav*_*pak 12

暧昧的论点是,当NSubstitute的参数进行比较,以它目前正在与工作的号召,以"说法的匹配"它(每次堆Arg.Blah被调用时,所涉及的参数匹配添加到该堆栈),它是无法解决哪个论点在哪里.

通常这是由于调用类似blah(null, null),使用单个参数匹配器排队,但也可能是由于在调用配置之外使用arg匹配器而导致堆栈失去同步,或者作为参数非虚方法.

版本1.8.0(在您的问题之后发布)包括对后一种情况的略微改进的检测,因此可能值得尝试.

除此之外,我有几次这个问题,并使用了以下(痛苦)的方法.

  • 单独运行测试并确保它通过
  • 弄清楚什么测试立即进行(通常可以猜测,但测试日志可以在这里帮助),并运行这两个测试.确认失败.
  • 查找任何调用都Arg.xyz可以在任一测试中排队参数匹配器.确保将其用作呼叫配置的一部分.有时可以通过注释掉行或用其他值替换arg匹配器来确定哪个调用有问题.
  • 确保没有调用非虚拟方法使NSubstitute混淆.

有时问题可能是由于之前的夹具造成的,所以您可能需要锻炼以前的夹具并在那里进行探索.:(