简体   繁体   English

Moq-在设置返回中使用It.IsAny会发生什么?

[英]Moq - What happens when using It.IsAny in a setup's return?

I am performing unit tests in C# using Moq. 我正在使用Moq在C#中执行单元测试。 One test in particular I have created an interface wrapper over System.Net.Mail.SmtpClient so that it can be mocked. 特别是一个测试,我在System.Net.Mail.SmtpClient创建了一个接口包装,以便可以对其进行模拟。

public class SmtpClient : ISmtpClient
{
    public string Host { get; set; }
    public int Port { get; set; }
    public ICredentialsByHost Credentials { get; set; }
    public bool EnableSsl { get; set; }

    public void Send(MailMessage mail)
    {
        var smtpClient = new System.Net.Mail.SmtpClient
        {
            Host = Host,
            Port = Port,
            Credentials = Credentials,
            EnableSsl = EnableSsl
        };

        smtpClient.Send(mail);
    }
}

In my tests of this wrapper, to ensure that the method Send() is called, I have mocked the interface, and in setting up the mock, I'm using the Setup() to assign values to the properties of that object. 在对该包装的测试中,为确保调用方法Send() ,我对接口进行了模拟,并在设置模拟时使用Setup()将值分配给该对象的属性。 In all documentation, I see that the .Return() of those setups are returning a specific value of the type that these methods are expecting. 在所有文档中,我看到这些设置的.Return()返回的是这些方法期望的类型的特定值。 However, before I understood it further, I instead used It.IsAny<T> in the returns. 但是,在进一步了解之前,我在返回中使用了It.IsAny<T>

[ClassInitialize]
public static void ClassInitialize(TestContext testContext)
{
    _smtpClientMock = new Mock<ISmtpClient>(MockBehavior.Strict);
    _smtpClientMock.Setup(x => x.Port).Returns(8080);
    _smtpClientMock.Setup(x => x.EnableSsl).Returns(false);
    _smtpClientMock.Setup(x => x.Host).Returns("host");
    _smtpClientMock.Setup(x => x.Credentials).Returns(It.IsAny<NetworkCredential>());

    _smtpClientMock.Setup(mockSend => mockSend.Send(It.IsAny<MailMessage>()));
}

[TestMethod]
public void WithValidMailMessageObject_WhenSendIsCalled_EmailClientCallsSmptClientToSendEmail()
{
    //Arrange

    //Act
    _smtpClientMock.Object.Send(new MailMessage());
    //Assert
    _smtpClientMock.Verify(checkMethodIsCalled => checkMethodIsCalled.Send(It.IsAny<MailMessage>()), Times.Once);
}

What I've noticed is that the tests passed. 我注意到的是测试通过了。 Since I haven't seen this elsewhere, I understand that this is not best practice. 由于我没有在其他地方看到此内容,因此我知道这不是最佳做法。 What I'm asking, is why is this not used, and what problems can come up with using It.IsAny<T>() inside the Return of a Moq's Setup() or a mocked object? 我要问的是为什么不使用它,以及在Moq的Setup()或模拟对象的Return中使用It.IsAny<T>()会带来什么问题?

It is meant to be used in Moq expressions for the filtering and matching of arguments. It打算在Moq表达式中用于过滤和匹配参数。

Allows the specification of a matching condition for an argument in a method invocation, rather than a specific argument value. 允许为方法调用中的参数而不是特定的参数值指定匹配条件。 "It" refers to the argument being matched. “它”是指匹配的参数。

It.IsAny<T>() is typically used when the actual argument value for a method call is not relevant. 当方法调用的实际参数值不相关时,通常使用It.IsAny<T>() When passed as a value outside of the Setup or Verify expressions It.IsAny<T>() passes the default value of the generic argument. 当作为SetupVerify表达式之外的值传递时, It.IsAny<T>()传递通用参数的默认值。 So for reference types it will pass null and so forth. 因此,对于引用类型,它将传递null等等。

While in your scenario it does not fail, it is generally advised not to use the It class for anything other than matching arguments passed to mocked dependencies. 虽然在您的方案中它不会失败,但是通常建议不要将It类用于传递给模拟依赖项的匹配参数以外的任何其他用途。

One typically uses the Returns to return a value of use when exercising a test. 在进行测试时,通常使用Returns返回使用值。 If a subject under test is expecting a value when a mock is invoked and instead the mock was Setup to return It.IsAny<T>() , then the test would behave in an unexpected manner. 如果被测对象在调用模拟Setup时期望一个值,而该模拟SetupSetup返回It.IsAny<T>() ,则测试将以意外的方式运行。

Given the following simple example 给出以下简单示例

public interface IDependency {
    string SomeMethod();
}

public MyClass {
    public bool MyMethod(IDependency input) {            
        var value = input.SomeMethod();

        var result = "Output" + value.ToUpper(); //<-- value should not be null

        return result != null;
    }
}

The following test will fail with a NullReferenceException because of the improper use of It.IsAny<T>() 由于It.IsAny<T>()使用不当,以下测试将失败并显示NullReferenceException

[TestMethod]
public void MyMethod_Should_Return_True() {
    //Arrange
    var mock = new Mock<IDependency>();
    mock.Setup(_ => _.SomeMethod()).Returns(It.IsAny<string>());
    var subject = new MyClass();
    var expected = true;

    //Act
    var actual = subject.MyMethod(mock.Object);

    //Assert
    Assert.AreEqual(expected, actual);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM