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

public interface IConfigProvider<T> {
    T GetConfig(int id);
    T GetConfig(string id);
}

被测试的类仅使用GetConfig的int版本,因此在SetUpFixture中,我执行以下操作来设置模拟的配置提供程序,该提供程序将始终返回相同的伪对象:
IConfigProvider<ConfigType> configProvider = Substitute.For<IConfigProvider<ConfigType>>();
configProvider.GetConfig(Arg.Any<int>()).Returns<ConfigType>(new ConfigType(/* args */);

如果该TestFixture是唯一正在运行的程序,则这绝对可以运行。但是,在同一程序集中的另一个TestFixture中,我检查是否收到了这样的调用:
connection.Received(1).SetCallbacks(Arg.Any<Action<Message>>(), Arg.Any<Action<long>>(), Arg.Any<Action<long, Exception>>());

如果这些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()

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

我尝试过的事情:
  • 如果重载是问题,则还添加configProvider.GetConfig(Arg.Any<string>()).Returns...
  • 我已经阅读了NSubstitute docs on argument matching,但是在那里找不到解决方案。如果必须同时为方法的int和string版本提供参数匹配器,则无法解决该问题。

  • 碰巧的是,我正在使用的测试只会调用值为0或1的GetConfig方法,因此我只能为这两个值提供Returns规范,而根本不使用匹配,但我想了解如何解决这更普遍。

    最佳答案

    模棱两可的参数是当NSubstitute将参数与其当前正在使用的调用进行比较时,与它具有的“参数匹配器”堆栈进行比较(每次调用Arg.Blah时,都会将参数匹配器添加到该堆栈中),并且无法解决哪个论点去哪儿。

    通常,这是由像blah(null, null)这样的调用引起的,其中有单个参数匹配器排队,但也可能是由于在调用配置之外使用了arg匹配器而导致堆栈不同步导致的。非虚拟方法。

    1.8.0版(在您的问题后发布)对后一种情况的检测略有改进,因此可能值得尝试。

    除此之外,我已经遇到过几次这个问题,并使用了以下(痛苦的)方法。

  • 独立运行测试,并确保它通过
  • 可以计算出要立即进行的测试(通常可以猜测,但是测试日志可以帮助您),然后仅运行这两个测试。确认失败。
  • 查找对Arg.xyz的任何调用,这些调用可能会使两个测试中的参数匹配器排队。确保将其用作调用配置的一部分。有时,可以通过注释掉行或用其他值替换arg匹配器来确定哪个调用有问题。
  • 确保没有对使NSubstitute感到困惑的非虚拟方法的调用。

  • 有时问题可能是由于先前的固定装置引起的,因此您可能需要锻炼先前的固定装置并在那里进行探索。 :(

    关于c# - NSubstitute-TestFixture 1导致TestFixture 2中的AmbiguousArgumentsException,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26805420/

    10-13 03:07