76

Hi I've been using moq for a while when I see this code.

I have to setup a return in one of my repo.

 mockIRole.Setup(r => r.GetSomething(It.IsAny<Guid>(), It.IsAny<Guid>(), 
                  It.IsAny<Guid>())).Returns(ReturnSomething);

I have three parameters and I just saw these in one of articles or blog on the net.

What is the use of It.Is<> or It.IsAny<> for an object? if I could use Guid.NewGuid() or other types then why use It.Is?

I'm sorry I'm not sure if my question is right or am I missing some knowledge in testing. But it seems like there is nothing wrong either way.

Dave Anderson
  • 11,836
  • 3
  • 58
  • 79
choopau
  • 2,209
  • 5
  • 21
  • 28
  • `It.IsAny()` means that you don't care what parameter was passed. `Guid.NewGuid()` means that you want to setup the method to return something only if the first parameter is equal to this new GUID. – Yacoub Massad May 05 '16 at 13:08
  • I don't know what you are asking. Moq is saying that, as long as the pass the correct types in, the call is valid and should return your object. – Jonesopolis May 05 '16 at 13:09
  • `It.Is<>` is useful to ensure you are calling your dependency with the correct values in the arguments – markusrambarkus May 05 '16 at 13:16
  • I've seen junior devs trying to use `It.IsAny()` to generate variables for test cases. It doesn't work :) I've also seen a lot of lazy test writers use `It.IsAny` for everything because they can't be arsed to figure out the actual variables to use.. – stuartd May 05 '16 at 14:35

2 Answers2

120

Using It.IsAny<>, It.Is<>, or a variable all serve different purposes. They provide increasingly specific ways to match a parameter when setting up or verifying a method.

It.IsAny

The method set up with It.IsAny<> will match any parameter you give to the method. So, in your example, the following invocations would all return the same thing (ReturnSomething):

role.GetSomething(Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid());

Guid sameGuid = Guid.NewGuid();
role.GetSomething(sameGuid, sameGuid, sameGuid);

role.GetSomething(Guid.Empty, Guid.NewGuid(), sameGuid);

It doesn't matter the actual value of the Guid that was passed.

It.Is

The It.Is<> construct is useful for setup or verification of a method, letting you specify a function that will match the argument. For instance:

Guid expectedGuid = ...
mockIRole.Setup(r => r.GetSomething(
                 It.Is<Guid>(g => g.ToString().StartsWith("4")), 
                 It.Is<Guid>(g => g != Guid.Empty), 
                 It.Is<Guid>(g => g == expectedGuid)))
         .Returns(ReturnSomething);

This allows you to restrict the value more than just any value, but permits you to be lenient in what you accept.

Defining a Variable

When you set up (or verify) a method parameter with a variable, you're saying you want exactly that value. A method called with another value will never match your setup/verify.

Guid expectedGuids = new [] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() };
mockIRole.Setup(r => r.GetSomething(expectedGuids[0], expectedGuids[1], expectedGuids[2]))
         .Returns(ReturnSomething);

Now there's exactly one case where GetSomething will return ReturnSomething: when all Guids match the expected values that you set it up with.

David Klempfner
  • 8,700
  • 20
  • 73
  • 153
Patrick Quirk
  • 23,334
  • 2
  • 57
  • 88
  • 1
    This is really what I need. I thought defining and using is really a different thing. It just that it.is are flexible to accept parameters. – choopau May 05 '16 at 18:44
  • Thank you this is very helpful, will add to the documentation regarding Mock. – Lostaunaum Jul 14 '17 at 15:57
  • Hi Patrick, in relation to your answer would you be so kind to explain to me further my problem in https://stackoverflow.com/questions/52854915/how-to-create-a-unit-test-for-adding-items-in-a-repository/52856751? Initially I passed a variable to my Verify method and it failed. However, when I changed it and passed an It.IsAny instead it passed. I am new to unit testing so I am still struggling to understand this. – Josh Monreal Oct 17 '18 at 14:13
13

If you look at the Quickstart documentation for Moq

Matching Arguments

// any value
mock.Setup(foo => foo.DoSomething(It.IsAny<string>())).Returns(true);


// matching Func<int>, lazy evaluated
mock.Setup(foo => foo.Add(It.Is<int>(i => i % 2 == 0))).Returns(true); 


// matching ranges
mock.Setup(foo => foo.Add(It.IsInRange<int>(0, 10, Range.Inclusive))).Returns(true); 


// matching regex
mock.Setup(x => x.DoSomething(It.IsRegex("[a-d]+", RegexOptions.IgnoreCase))).Returns("foo");
Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • 1
    What if we don't care about *any* param passed in? Imagine a method with four or more params, it get's pretty long. – FoxDeploy Oct 26 '21 at 13:11