我正在使用 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 版本提供参数匹配器,我不知道该怎么做。
碰巧,我正在使用的测试只会调用 GetConfig
值为 0 或 1 的方法,所以我可以只提供 Returns
这两个值的规范,根本不使用匹配,但我想了解如何更普遍地解决这个问题。
最佳答案
参数不明确是指当 NSubstitute 将参数与它当前正在使用的调用进行比较时,与它拥有的“参数匹配器”堆栈(每次 Arg.Blah
被调用时,参数匹配器被添加到那个堆栈),并且它无法解决哪个参数去哪里。
通常这是由于像 blah(null, null)
这样的调用导致的,只有一个参数匹配器在排队,但也可能是由于堆栈不同步导致的在调用配置之外使用的参数匹配器,或作为非虚拟方法的参数。
1.8.0 版(在您提出问题后发布)对后一种情况的检测略有改进,因此值得一试。
除此之外,我遇到过几次这个问题并使用了以下(痛苦的)方法。
- 单独运行测试并确保它通过
- 找出立即运行的测试(通常可以猜测,但测试日志在这里可以提供帮助),然后只运行这两个测试。确认失败。
- 查找对
Arg.xyz
的任何调用,这些调用可能会在任一测试中对参数匹配器进行排队。确保它用作调用配置的一部分。有时可以通过注释行或将 arg 匹配器替换为其他值来确定哪个调用有问题。 - 确保没有调用会混淆 NSubstitute 的非虚拟方法。
有时问题可能是由于之前的夹具引起的,因此您可能需要锻炼之前的夹具并在那里进行探索。 :(
关于c# - NSubstitute - TestFixture 1 在 TestFixture 2 中导致 AmbiguousArgumentsException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26805420/