使用 out 参数在 NSubstitute 模拟方法中返回不同的值
returning different values in an NSubstitute mock method with an out parameter
给定一个模拟的方法...
public bool TryReceive(out T message, TimeSpan millisecondsToWait)
- 我希望在前两次调用中设置不同的消息,并且 return
真的。
- 后续调用 return 错误。
我尝试了一些变体,在任何一种情况下,lambda 表达式都会执行一次,并且再也不会执行。 NSubstitute 似乎 缓存第一个 return 值 ,并一遍又一遍地使用相同的值。
我已经试过了...
TCR @out;
var container = new AutoSubstitute();
var mb = container.Resolve<IMessageBuffer<TCR>>();
mb.TryReceive(out @out, Arg.Any<TimeSpan>()).Returns(
_ => { _[0] = buy; return true; },
_ => { _[0] = sell; return true; },
_ => { _[0] = null; return false; });
我已经试过了:
bool? bs = true;
TCR @out;
var container = new AutoSubstitute();
var mb = container.Resolve<IMessageBuffer<TCR>>();
mb.TryReceive(out @out, Arg.Any<TimeSpan>()).Returns(
_ =>
{
if (bs == true)
{
_[0] = buy;
bs = false;
return true;
}
if (bs == false)
{
_[0] = sell;
bs = null;
return true;
}
_[0] = null;
return false;
});
我能想到的唯一选择是提供缓冲区的完整替代实现以用于测试目的。我的感觉是这样documentation,应该可以吧
编辑
我一直无法使用 NSubstitute 实现此功能,但是如果我使用
提供 IMessageBuffer<TCR>
的模拟实现
// mock buffer will return the necessary values by maintaining
// the relevant state internally.
container.Provide<IMessageBuffer<TCR>>(new MockBuffer());
它工作正常,所以这不是生命周期问题。不知何故,NSubstitute 似乎只在第一次调用模拟方法,并重用该值(或以 似乎 重用该值的方式运行)- 非常奇怪。
NSubstitute 在 out
和 ref
参数方面有些困难。
问题是当我们存根时:
mb.TryReceive(out @out, Arg.Any<TimeSpan>()).Returns(...)
这只会在@out
为原始值时执行。这个值会在第一次调用时改变,所以 Returns
lambda 不会再次执行(NSub 认为这是一个不同的、不匹配的调用)。
解决此问题的最简单方法是切换到 ReturnsForAnyArgs(...)
:
mb.TryReceive(out @out, Arg.Any<TimeSpan>()).ReturnsForAnyArgs(action0, action1, action2);
这将适用于所有 TryReceive
调用,无论参数值如何,因此 lambda 应该始终执行。这样做的缺点是,如果您只想 运行 用于第二个参数的特定值,那么您必须将该逻辑放在 lambda 中(而不是使用参数匹配器)。
给定一个模拟的方法...
public bool TryReceive(out T message, TimeSpan millisecondsToWait)
- 我希望在前两次调用中设置不同的消息,并且 return 真的。
- 后续调用 return 错误。
我尝试了一些变体,在任何一种情况下,lambda 表达式都会执行一次,并且再也不会执行。 NSubstitute 似乎 缓存第一个 return 值 ,并一遍又一遍地使用相同的值。
我已经试过了...
TCR @out;
var container = new AutoSubstitute();
var mb = container.Resolve<IMessageBuffer<TCR>>();
mb.TryReceive(out @out, Arg.Any<TimeSpan>()).Returns(
_ => { _[0] = buy; return true; },
_ => { _[0] = sell; return true; },
_ => { _[0] = null; return false; });
我已经试过了:
bool? bs = true;
TCR @out;
var container = new AutoSubstitute();
var mb = container.Resolve<IMessageBuffer<TCR>>();
mb.TryReceive(out @out, Arg.Any<TimeSpan>()).Returns(
_ =>
{
if (bs == true)
{
_[0] = buy;
bs = false;
return true;
}
if (bs == false)
{
_[0] = sell;
bs = null;
return true;
}
_[0] = null;
return false;
});
我能想到的唯一选择是提供缓冲区的完整替代实现以用于测试目的。我的感觉是这样documentation,应该可以吧
编辑
我一直无法使用 NSubstitute 实现此功能,但是如果我使用
提供IMessageBuffer<TCR>
的模拟实现
// mock buffer will return the necessary values by maintaining
// the relevant state internally.
container.Provide<IMessageBuffer<TCR>>(new MockBuffer());
它工作正常,所以这不是生命周期问题。不知何故,NSubstitute 似乎只在第一次调用模拟方法,并重用该值(或以 似乎 重用该值的方式运行)- 非常奇怪。
NSubstitute 在 out
和 ref
参数方面有些困难。
问题是当我们存根时:
mb.TryReceive(out @out, Arg.Any<TimeSpan>()).Returns(...)
这只会在@out
为原始值时执行。这个值会在第一次调用时改变,所以 Returns
lambda 不会再次执行(NSub 认为这是一个不同的、不匹配的调用)。
解决此问题的最简单方法是切换到 ReturnsForAnyArgs(...)
:
mb.TryReceive(out @out, Arg.Any<TimeSpan>()).ReturnsForAnyArgs(action0, action1, action2);
这将适用于所有 TryReceive
调用,无论参数值如何,因此 lambda 应该始终执行。这样做的缺点是,如果您只想 运行 用于第二个参数的特定值,那么您必须将该逻辑放在 lambda 中(而不是使用参数匹配器)。