9

Suppose I have the following entity:

public class User
{
    public int Id { get; set; }
    public string Username { get; set; }
    public Guid UserGuid { get; set; }
    public Guid ConfirmationGuid { get; set; }
}

And the following interface method:

void CreateUser(string username);

Part of the implementation should create two new GUIDs: one for UserGuid, and another for ConfirmationGuid. They should do this by setting the values to Guid.NewGuid().

I already have abstracted Guid.NewGuid() using an interface:

public interface IGuidService
{
    Guid NewGuid();
}

So I can easily mock this when only one new GUID is needed. But I'm not sure how to mock two different calls to the same method, from within one method, such that they return different values.

Jerad Rose
  • 15,235
  • 18
  • 82
  • 153

2 Answers2

11

If you are using Moq, you can use:

mockGuidService.SetupSequence(gs => gs.NewGuid())
    .Returns( ...some value here...)
    .Returns( ...another value here... );

I suppose you could also do the following:

mockGuidService.Setup(gs => gs.NewGuid())
    .Returns(() => ...compute a value here...);

Still, unless you are just supplying a random value within the return function, knowledge of order still seems to be important.

Matt H
  • 7,311
  • 5
  • 45
  • 54
  • But wouldn't this assume that I'm setting the properties in the implementation in a certain sequence? Isn't this clouding the concerns of my test? In other words, these fields could be set in any order, and if for some reason I change this order without updating my tests, my tests should ideally still pass. – Jerad Rose Jul 21 '12 at 04:13
  • Well... you're getting into state vs. behavioral testing a bit. I'm not sure how else to answer the question without making the assumption of knowledge about call order. – Matt H Jul 21 '12 at 04:23
  • 3
    If I understand correctly, you don't want to have `Assert.AreEqual(guid1, user.UserGuid); Assert.AreEqual(guid2, user.ConfirmationGuid);` fail if you change the order of assignment. Instead you should use some sort of collection assert that is independent of order (available in both nunit and mstest): `CollectionAssert.AreEquivalent(new[] { guid1, guid2 }, new[] { user.UserGuid, user.ConfirmationGuid });` – Mike Zboray Jul 21 '12 at 05:04
  • @MattH, there's a good chance I'm blurring the lines between state & behavioral testing. Do you suggest the design of my test should be reconsidered? – Jerad Rose Jul 21 '12 at 13:34
  • @mikez, yes that in combination w/ Matt's answer should do the trick. Thanks guys. – Jerad Rose Jul 21 '12 at 14:33
5

If you can't use Moq as in @Matt's example then you can build your own class which will do essentially the same thing.

public class GuidSequenceMocker
{
    private readonly IList<Guid> _guidSequence = new[]
                                                     {
                                                         new Guid("{CF0A8C1C-F2D0-41A1-A12C-53D9BE513A1C}"),
                                                         new Guid("{75CC87A6-EF71-491C-BECE-CA3C5FE1DB94}"),
                                                         new Guid("{E471131F-60C0-46F6-A980-11A37BE97473}"),
                                                         new Guid("{48D9AEA3-FDF6-46EE-A0D7-DFCC64D7FCEC}"),
                                                         new Guid("{219BEE77-DD22-4116-B862-9A905C400FEB}") 
                                                     };
    private int _counter = -1;

    public Guid Next()
    {
        _counter++;

        // add in logic here to avoid IndexOutOfRangeException
        return _guidSequence[_counter];
    }
}
Kane
  • 16,471
  • 11
  • 61
  • 86