How to Repeat a return value

332 views
Skip to first unread message

Candy Chiu

unread,
Feb 26, 2013, 2:14:46 PM2/26/13
to nsubs...@googlegroups.com
For a particular function, I need to return value1 for the first call, then value2 for all subsequent calls.  How do I specify this behavior?

           stub.Func().Returns(value1, Repeat(value2));

David Tchepak

unread,
Feb 26, 2013, 6:22:02 PM2/26/13
to nsubs...@googlegroups.com
stub.Func().Returns(value1, value2);

This will repeat value2 after it has returned value1.


On Wed, Feb 27, 2013 at 6:14 AM, Candy Chiu <candy....@gmail.com> wrote:
For a particular function, I need to return value1 for the first call, then value2 for all subsequent calls.  How do I specify this behavior?

           stub.Func().Returns(value1, Repeat(value2));

--
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?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Candy Chiu

unread,
Feb 27, 2013, 10:56:15 AM2/27/13
to nsubs...@googlegroups.com
David,

Is there a way to repeat the values other than the last one?

stub.Func().Returns(Repeat(value1, 3), Repeat(value2, 3), value3);

instead of 

stub.Func().Returns(value1, value1, value1, value2, value2, value2, value3);

Thanks.

Candy Chiu

unread,
Feb 27, 2013, 3:36:44 PM2/27/13
to nsubs...@googlegroups.com
Along the same line, how do I specify multiple Do's for When?
stub.WhenForAnyArgs(x => x.DoWork())
      .Do(x => CallbackForFirstCall())
      .Do(x => CallbackForSecondCall());


On Tuesday, February 26, 2013 6:22:02 PM UTC-5, David Tchepak wrote:

Candy Chiu

unread,
Feb 27, 2013, 5:09:46 PM2/27/13
to nsubs...@googlegroups.com
Just want to supplement the question with some background info.

I have functions that returns multiple values via either ref or out.  I need to specify each call's return value similar to how the regular Returns works.

Thanks. 

David Tchepak

unread,
Feb 27, 2013, 5:15:10 PM2/27/13
to nsubs...@googlegroups.com
First I need to put in the usual disclaimer about over-specifying tests. If you need this much real behaviour from a substitute you may be testing too much or you may be better using a real implementation (or a hand-rolled test double that behaves exactly how you want).

That said, you can get more control over what is returned by passing a function that manages it for you:

stub.Func().Returns(x => GetNextValue());

Here's an example of a structure that handles this for you:

    public interface IFoo { string Stuff(); }

    [Test]
    public void Example()
    {
        var foo = Substitute.For<IFoo>();
        var returns = ReturnsQueue<string>
            .FirstRepeat("hello", 2)
            .ThenRepeat("world", 3)
            .Then("!");

        foo.Stuff().Returns(x => returns.Next());

        for (int i = 0; i < 6; i++)
        {
            Console.WriteLine(foo.Stuff());
        }

        /* outputs:
        hello
        hello
        world
        world
        world
        !
        */ 
    }

    public class ReturnsQueue<T>
    {
        public static ReturnsQueue<T> FirstRepeat(T value, int times) { return new ReturnsQueue<T>().ThenRepeat(value, times); }
        public static ReturnsQueue<T> First(T value) { return new ReturnsQueue<T>().Then(value); } 
        private readonly Queue<Func<T>> _returns = new Queue<Func<T>>();
        private ReturnsQueue() { }
        public ReturnsQueue<T> Then(T value) { _returns.Enqueue(() => value); return this; }
        public ReturnsQueue<T> ThenRepeat(T value, int times)
        {
            foreach (var v in Enumerable.Repeat(value, times)) { Then(v); } 
            return this;
        }
        public T Next() { return _returns.Dequeue().Invoke(); }
    }


David Tchepak

unread,
Feb 27, 2013, 5:16:20 PM2/27/13
to nsubs...@googlegroups.com
NSubstitute doesn't support this. You'll need to add that logic into the callback itself.

David Tchepak

unread,
Feb 27, 2013, 5:18:44 PM2/27/13
to nsubs...@googlegroups.com
I think you could use a similar approach to the ReturnsQueue I posted earlier to set multiple ref/out values, with a different value set each time the queue.Next() is called.
Sound OK?

David Tchepak

unread,
Feb 27, 2013, 5:49:02 PM2/27/13
to NSubstitute
Was just pointed out to me that this can be done more simply with the
Returns(T value, params T values) overload:

[Test]
public void Example2()
{
var foo = Substitute.For<IFoo>();
foo.Stuff().Returns("hello", Repeat("world",
3).Concat(Repeat("!", 2)).ToArray());

// produces: "hello", "world", "world", "world", "!", "!"
}

The queue approach may be useful for the different callback behaviours
required for your When..Do callbacks though, or if additional logic is
required to produce values for some reason.
> >>> an email to nsubstitute...@**googlegroups.com.
> >>> To post to this group, send email to nsubs...@googlegroups.com.
>
> >>> Visit this group athttp://groups.google.com/**group/nsubstitute?hl=en<http://groups.google.com/group/nsubstitute?hl=en>
> >>> .
> >>> For more options, visithttps://groups.google.com/**groups/opt_out<https://groups.google.com/groups/opt_out>
> >>> .
Reply all
Reply to author
Forward
0 new messages