It.IsAny <t>()用作模拟对象</t>

时间:2014-03-13 08:43:22

标签: c# unit-testing moq

使用moq,通常使用T为接口类型Mock.Of<T>()提供模拟。但是,It.IsAny<T>()或者T返回一个表达式,它似乎也可以用作对象来代替It.IsAny<T>()类型的对象。我只看到Setup()用于定义Mock.Of<T>()中方法调用的参数。 It.IsAny<T>()It.IsAny<T>()之间有什么区别(除了语法之外)?在任何情况下都应使用Mock.Of<T>()来模拟new UserService()吗?

以下是我要问的一个例子,我将以Ufuk的答案为基础。提供给It.IsAny<IUserRepository>()的模拟可以是Mock.Of<IUserRepository>()Assert.IsTrue()。在这种情况下,我不想对这些模拟设置任何特殊的东西,只是它们存在以满足编译器。出于这些测试的目的,IUserRepository语句与提供的It.IsAny<IUserRepository>()无关。问题是:在此实例中,Mock.Of<IUserRepository>()[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; } } 在功能上是否相同?

{{1}}

1 个答案:

答案 0 :(得分:7)

It.IsAny<T>用于跳过模拟方法参数中的验证。

serviceMock.Setup(mock => mock.GetUser(It.IsAny<int>())).Returns(someResult);

您必须在模拟回调中传递一个整数作为参数才能进行测试编译。您可能不知道将哪些值发送到模拟组件(对于引用类型通常是真的),或者您甚至可能不关心。 It.IsAny<T>()为您提供编写测试而不会超出规范。

It.IsAny<T>()会返回T的实例,而不是Mock<T>,因此它不是模拟。

看看这些测试用例:

[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; }
}

第二次测试失败,因为Moq无法将模拟实例识别为参数值。当您想要使用谓词参数中包含的单个设置快速创建模拟时,Mock.Of<T>()似乎很有用。

<强>更新

我在你的例子中改写了测试。

[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);
}

两个测试都失败,因为It.IsAny<T>()返回null。如果您使用过Mock.Of<T>(),则会创建一个具有默认行为的模拟。这意味着在这种情况下它们在功能上也不相同。