Reputation: 16106
Using moq, it is usual to provide a mock for an interface type T
by using Mock.Of<T>()
. But alternatively It.IsAny<T>()
returns an Expression that also seems to be usable as an object in place of an object of type T
. I've only seen It.IsAny<T>()
used to define arguments for method calls in Setup()
. What is the difference between Mock.Of<T>()
and It.IsAny<T>()
(besides syntax obviously)? Are there any circumstances where It.IsAny<T>()
should be used to provide a mock over Mock.Of<T>()
?
Here is an example of what I'm asking, which I'll build on Ufuk's answer. The mock provided to new UserService()
can be either It.IsAny<IUserRepository>()
or Mock.Of<IUserRepository>()
. In this case, I'm not interested in setting up anything special about these mocks, only that they exist to satisfy the compiler. The Assert.IsTrue()
statements are agnostic to the supplied IUserRepository
for the purposes of these tests. The question is: are It.IsAny<IUserRepository>()
and Mock.Of<IUserRepository>()
functionally equivalent in this instance?
[TestFixture]
public class MoqTests
{
[Test]
public void TestInitializationWithItIsAny()
{
var subject = new UserService( It.IsAny<IUserRepository>() ); // It.IsAny<T>
_userService.RegisterUser("abc");
Assert.IsTrue( _userService.IsInitialized() );
}
[Test]
public void TestInitializationWithMockOf()
{
var subject = new UserService( Mock.Of<IUserRepository>() ); // Mock.Of<T>
_userService.RegisterUser("abc");
Assert.IsTrue( _userService.IsInitialized() );
}
}
public class UserService
{
private readonly IUserRepository _userRepository;
private bool _isInitialized = false;
public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public bool RegisterUser(string userName)
{
_isInitialized = true;
User user = new User { UserName = userName, CreatedOn = DateTime.Now };
return _userRepository.RegisterUser(user);
}
public bool IsInitialized()
{
return _isInitialized;
}
}
public interface IUserRepository
{
bool RegisterUser(User user);
}
public class User
{
public string UserName { get; set; }
public DateTime CreatedOn { get; set; }
}
Upvotes: 3
Views: 9972
Reputation: 38478
It.IsAny<T>
is used to skip validation in mocked method parameters.
serviceMock.Setup(mock => mock.GetUser(It.IsAny<int>())).Returns(someResult);
You have to pass an integer as a parameter in mock callback to make the test compile. You may not know what value will be sent to mocked component(usually true for reference types) or you may not even care. It.IsAny<T>()
provides you to write tests without over specification.
It.IsAny<T>()
returns an instance of T
, not Mock<T>
so it's not a mock.
Take a look at these test cases:
[TestFixture]
public class MoqTests
{
private Mock<IUserRepository> _repository;
private UserService _userService;
[SetUp]
public void Setup()
{
_repository = new Mock<IUserRepository>(MockBehavior.Strict);
_userService = new UserService(_repository.Object);
}
[Test]
public void RegisterUserWithItIsAny()
{
_repository.Setup(item => item.RegisterUser(It.IsAny<User>())).Returns(true);
bool result = _userService.RegisterUser("abc");
Assert.True(result);
}
[Test]
public void RegisterUserWithMockOf()
{
_repository.Setup(item => item.RegisterUser(Mock.Of<User>())).Returns(true);
bool result = _userService.RegisterUser("abc");
Assert.True(result);
}
[TearDown]
public void TearDown()
{
_repository.VerifyAll();
}
}
public class UserService
{
private readonly IUserRepository _userRepository;
public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public bool RegisterUser(string userName)
{
User user = new User { UserName = userName, CreatedOn = DateTime.Now };
return _userRepository.RegisterUser(user);
}
}
public interface IUserRepository
{
bool RegisterUser(User user);
}
public class User
{
public string UserName { get; set; }
public DateTime CreatedOn { get; set; }
}
Second test fails because Moq does not recognize the mock instance as parameter value. Mock.Of<T>()
seems useful when you want to create mocks quickly with a single setup contained in predicate parameter.
Update:
I rewrote the test just as in your examples.
[SetUp]
public void Setup()
{
_userService = new UserService(It.IsAny<IUserRepository>());
}
[Test]
public void RegisterUserWithItIsAny()
{
bool result = _userService.RegisterUser("abc");
Assert.True(result);
}
[Test]
public void RegisterUserWithMockOf()
{
bool result = _userService.RegisterUser("abc");
Assert.True(result);
}
Both tests fail because It.IsAny<T>()
returns null. If you have used Mock.Of<T>()
it would create a mock with default behavior. That means they are not functionally equivalent in this case too.
Upvotes: 7