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

ⅰ亾dé卋堺 提交于 2021-02-04 07:29:45

问题


I am performing unit tests in C# using Moq. One test in particular I have created an interface wrapper over System.Net.Mail.SmtpClient so that it can be mocked.

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. In all documentation, I see that the .Return() of those setups are returning a specific value of the type that these methods are expecting. However, before I understood it further, I instead used It.IsAny<T> in the returns.

[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?


回答1:


It is meant to be used in Moq expressions for the filtering and matching of arguments.

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. When passed as a value outside of the Setup or Verify expressions It.IsAny<T>() passes the default value of the generic argument. So for reference types it will pass null and so forth.

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.

One typically uses the Returns to return a value of use when exercising a test. 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.

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>()

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


来源:https://stackoverflow.com/questions/49761943/moq-what-happens-when-using-it-isany-in-a-setups-return

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!