问题
Given a method with which to mock...
public bool TryReceive(out T message, TimeSpan millisecondsToWait)
- I wish to set different messages on the first two calls, and return true.
- Subsequent calls return false.
I have tried a few variations, and in either case, the lambda expression is executed once, and never again. NSubstitute seems to be caching the first return value, and using the same value over and over.
I have tried this...
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; });
and I have tried this:
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;
});
The only option I can think of is to provide a complete substitute implementation of the buffer for test purposes. My feeling is that given this documentation, it should be possible.
edit
I have been unable to get this working using NSubstitute, however if I provide a mock implementation of the IMessageBuffer<TCR>
using
// mock buffer will return the necessary values by maintaining
// the relevant state internally.
container.Provide<IMessageBuffer<TCR>>(new MockBuffer());
it works correctly, so it's not a lifetimescope issue. Somehow NSubstitute seems to be calling the mocked out method only the first time, and reusing the value (or operating in such a way that it seems to reuse the value) - very strange.
回答1:
NSubstitute struggles a bit with out
and ref
parameters.
The problem is that when we stub:
mb.TryReceive(out @out, Arg.Any<TimeSpan>()).Returns(...)
this will only execute when @out
is the original value. This value will change the first time it is called, so the Returns
lambda won't execute again (NSub thinks it is a different, non-matching call).
The easiest way to work-around this is to switch to ReturnsForAnyArgs(...)
:
mb.TryReceive(out @out, Arg.Any<TimeSpan>()).ReturnsForAnyArgs(action0, action1, action2);
This will work for all TryReceive
calls, regardless of the parameter values, so the lambda should always execute. The downside of this is that if you want this to only run for specific values of the second argument then you'll have to put that logic inside the lambda (rather than using an argument matcher).
来源:https://stackoverflow.com/questions/38075513/returning-different-values-in-an-nsubstitute-mock-method-with-an-out-parameter