C# Mocking a method to return a different value when called a second time using NSubstitue

341 views
Skip to first unread message

Srinath Upadhya

unread,
Mar 5, 2018, 10:53:57 PM3/5/18
to NSubstitute
_logbookEntryDalMock.GetEntryById(Arg.Any<string>(), Arg.Any<string>()).Returns(updatedEvent) ;
            _logbookEntryDalMock.GetEntryById(Arg.Any<string>(), Arg.Any<string>()).ReturnsForAnyArgs(previousevent) ;
            _logbookEntryDalMock.GetEntryById(Arg.Any<string>(), Arg.Any<string>()).ReturnsForAnyArgs(nextintevent1);

My main call is 

var res = _logRepositoryTest.MoveUserEntryUpOrDown(deviceId, updatedEvent.Id, previousevent.Id, nextintevent1.Id);
Inside this method  GetEntryById() is called thirce but i want to assign different values to each call (as mentioned above) currently only the last call value is being taken how to acheive this?


David Tchepak

unread,
Mar 5, 2018, 10:57:18 PM3/5/18
to nsubs...@googlegroups.com
Hello,

Try using multiple arguments in `Returns`:


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+unsubscribe@googlegroups.com.
To post to this group, send email to nsubs...@googlegroups.com.
Visit this group at https://groups.google.com/group/nsubstitute.
For more options, visit https://groups.google.com/d/optout.

Mike Taylor

unread,
Jan 9, 2019, 6:21:31 AM1/9/19
to NSubstitute

Did this work, because I'm trying it out and I'm gettings the same behaviour as you, whereby it returns the last item we assigned to it.  

Mike Taylor

unread,
Jan 9, 2019, 6:32:32 AM1/9/19
to NSubstitute


On Wednesday, January 9, 2019 at 11:21:31 AM UTC, Mike Taylor wrote:

Did this work, because I'm trying it out and I'm gettings the same behaviour as you, whereby it returns the last item we assigned to it.  

for example if i run this. 

    [TestMethod]
        public void Test()
        {
            T1 j = Substitute.For<T1>();
            j.getMessage().Returns("h");
            j.getMessage().Returns("j");

            var t1 = j.getMessage();
            var t2 = j.getMessage();

            TestAssetion.Assert.AreEqual("h", t1);
            TestAssetion.Assert.AreEqual("j", t2);
        }

        public interface T1
        {
            string getMessage();
        }

t1 and t2 are set to j.

David Tchepak

unread,
Jan 9, 2019, 6:45:50 AM1/9/19
to nsubs...@googlegroups.com
Hi Mike,

When a substitute gets called, NSubstitute will search from the most recent `Returns` backwards until it finds a match for that call. So if you specify a more recent `Returns` for a call it will overwrite previous returns for that call (assuming the specified args are the same or more general). For example, consider:

sub.Add(Arg.Any<Int>(), Arg.Any<Int>()).Returns(42); // (c)
sub.Add(1, 2).Returns(3); // (b)
sub.Add(3, 4).Returns(7); // (a)

If we call `Add(1, 2)` now, NSubstitute will check the most recent returns specified at (a). This doesn't match the arguments, as it expects `3, 4`, but got `1, 2`. Next it will check (b), which does match, so it will return `3`. If we call `Add(10, 10)`, it will check (a) and (b), which won't match, then also check (c), which in this case does match, so `42` is returned. If we then specified `sub.Add(Arg.Any<Int>(), Arg.Any<Int>()).Returns(999);`, this will match all calls from that point on, and therefore effectively overwrite all the previously configured return values.
 
There are a few ways to return different values each time for a particular call, the easiest probably being the multiple `Returns` arguments mentioned earlier:

_logbookEntryDalMock.GetEntryById(Arg.Any<string>(), Arg.Any<string>()).Returns(updatedEvent, previousevent, nextintevent1);

Hope this helps.
Regards,
David


On Wed, Jan 9, 2019 at 10:21 PM Mike Taylor <mike.t...@live.com> wrote:

Did this work, because I'm trying it out and I'm gettings the same behaviour as you, whereby it returns the last item we assigned to it.  

--
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.

Mike Taylor

unread,
Jan 9, 2019, 7:11:19 AM1/9/19
to NSubstitute
Hi David,

Thank you for getting back to me. 

The function that I'm calling doesn't take any params, so in my case, I'm requesting data from a database, hence why i'm mocking it out and with what you are proposing i don't think it will work. 

1st call, GetData(), returns null;

CreateData(), returns bool to state the success

2nd call, GetData(), returns the data in the database. 


So alternatively, when i do the CreateData() it now returns the data from the database as well. 

Thanks,

Mike

David Tchepak

unread,
Jan 9, 2019, 7:34:27 AM1/9/19
to nsubs...@googlegroups.com
When you have inter-related calls like that it gets a bit trickier. Mandatory disclaimer: if we need to have a more realistic implementation like this, it might be worth implementing a test variant of the class/interface instead of configuring it with a mocking library. We can then also test this test code to make sure it is adhering to the correct contract. I normally find mocking works best when we really don't care about a specific implementation of a dependency, we just want to make sure our code under test calls a dependency when expected and uses returned values correctly, independent of any particular implementation or call ordering.

With that out of the way, here's one way of doing something like this... :)

    DbData data = null;
    sub.GetData().Returns(x => data);
    sub.CreateData().Returns(x => {
        data = new DbData("my sample data");
        return true;
    });

This will make `GetData()` return whatever is in the `data` variable. Initially it is `null`, but after a call to `CreateData()`, it will be populated with sample data.

It might be worth seeing if you can instead split up the design of the tests (or the production code if necessary) a bit to reduce this coupling. For example, we could test:

[Test] public void CreatesDataIfNoDataPresent() {
    sub.GetData().Returns(null);
    classUnderTest.DoStuff();
    sub.Received().CreateData();
}

[Test] public void DoesNotCreateDataIfAlreadyHasData() {
    sub.GetData().Returns(data);
    classUnderTest.DoStuff();
    sub.DidNotReceive().CreateData();
}

[Test] public void UsesDataCorrectly() {
    // for this case it shouldn't matter if data was already there, or was added via CreateData()
    sub.GetData().Returns(data);
    classUnderTest.DoStuff();
    Assert(stuffHappenedWithData);
}

[Test] public void IfCreateDataFails() {
    sub.GetData().Returns(null);
    sub.CreateData().Returns(false);
    classUnderTest.DoStuff();
    Assert(theRightThingHappened);
}

I think this side-steps the coupling issue between calls to this dependency, and will hopefully provide us with a very specifically-failing test if something is not working (rather than having one larger test breaking for a number of potential reasons). 

YMMV of course, and I understand the actual case you're looking at may be much more complicated etc., but thought it was worth mentioning in case it gave you some ideas for alternate approaches that may work more nicely here.

Regards,
David



Reply all
Reply to author
Forward
0 new messages