Mock method with out parameter (several variants)

268 views
Skip to first unread message

Alexander Buts

unread,
Jul 31, 2014, 9:34:59 AM7/31/14
to nsubs...@googlegroups.com

Is that bug or known behavior?

using System;
using NSubstitute;
using NUnit.Framework;

namespace TestTimer.Test
{
public interface IInterface
{
bool TryGet(ulong id, out DateTime value);
}

[TestFixture]
public class Test
{
[Test]
public void Test1()
{
var mock = Substitute.For<IInterface>();

DateTime value1;
DateTime value2;
DateTime value3;
mock.TryGet(Arg.Is<ulong>(100), out value1).Returns(x => { x[1] = new DateTime(100); return true; });
mock.TryGet(Arg.Is<ulong>(200), out value2).Returns(x => { x[1] = new DateTime(200); return true; });
mock.TryGet(Arg.Is<ulong>(300), out value3).Returns(x => { x[1] = new DateTime(300); return true; });

DateTime resValue;
var res1 = mock.TryGet(100, out resValue);
Assert.IsTrue(res1);
var res2 = mock.TryGet(200, out resValue);
Assert.IsTrue(res2); // NOTE: Will fail here because resValue is already assigned
var res3 = mock.TryGet(300, out resValue);
Assert.IsTrue(res3);
}
}
}

David Tchepak

unread,
Aug 3, 2014, 3:08:24 AM8/3/14
to nsubs...@googlegroups.com
Hi Alexander,

This is a known behaviour, although it is not a particularly obvious one.

In this case the variables `value1`, `value2` and `value2` are initialised to empty dates (`default(DateTime)`). The calls like `TryGet(200, default(DateTime))` then get stubbed out to return specific values for those empty dates.

In the code being tested `resValue` is used. It gets the first call `mock.TryGet(100, out resValue)` which sets `resValue` to `new DateTime(100)`. So the next call looks like `mock.TryGet(200, DateTime(100))`, which doesn't match the `TryGet(200, default(DateTime))` initially stubbed.

In other words, calling the method updates the output variable, which means it no longer matches the stubbed call.

To work around this you'll need a new `resValue` variable each time, which isn't always practical for real code. It might be worth trying `ReturnsForAnyArgs` instead, like:

DateTime value1;
mock.TryGet(0, out value1).ReturnsForAnyArgs(x => { /* logic here to set output variable based on x[0] */ return true; });

This should match for any value of the `value1` variable.

Hope this helps.

Regards,
David





--
You received this message because you are subscribed to the Google Groups "NSubstitute" group.
To unsubscribe from this group and stop receiving emails from it, send an email to nsubstitute...@googlegroups.com.
To post to this group, send email to nsubs...@googlegroups.com.
Visit this group at http://groups.google.com/group/nsubstitute.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages