使用Moq在模拟对象中定义方法实现

本文关键字:定义 方法 实现 对象 Moq 模拟 使用 | 更新日期: 2023-09-27 18:03:41

情况就是这样。我有一个异步调用,所以我需要为此创建一个中间层,以便能够测试它。

request.BeginGetResponse(new AsyncCallback(LoginCallback), requestState);

因此,为了能够在没有实际请求的情况下进行测试,我创建了一个可以模拟的接口。

public interface IRequestSender
    {
        void Send(HttpWebRequest request, AsyncCallback internalCallback, object requestState);
    }

然后在实现中,我可以使用上面的调用,我可以提供一些模拟类来调用我的回调方法,无论请求是否有效。我的模拟类是这样的。

public class RequestSenderMock : IRequestSender
    {
        public void Send(HttpWebRequest request, AsyncCallback internalCallback, object requestState)
        {
            var result = new Mock<IAsyncResult>();
            result.Setup(x => x.AsyncState).Returns(requestState);
            internalCallback(result.Object);
        }
    }

我现在可以很容易地在单元测试中创建模拟对象并使用它。但是当我创建

var sender = new Mock<RequestSenderMock>();

我无法验证这个对象的调用计数。

sender.Verify(x => x.Send(It.IsAny<HttpWebRequest>(), It.IsAny<AsyncCallback>(), It.IsAny<object>()), Times.Once());

它说我的方法需要是虚的。有没有一种方法可以做到这一点,而不使我的方法虚拟?如果我能在使用接口时以某种方式指定方法实现,那将是最好的。

var sender = new Mock<IRequestSender>();

并以某种方式使用Setup方法或其他方法在这个模拟对象上实现。那我就把模拟课撤了。这可能吗?你有什么建议?

使用Moq在模拟对象中定义方法实现

我发现您正在创建一个手动模拟并使用一个模拟框架来模拟它(模拟一个模拟)是令人困惑的。我会考虑将您的自定义函数移到一些实用程序类中,并使用回调来代替。

的例子:

public class RequestSenderHelpers
{
    public static void Send(HttpWebRequest request, AsyncCallback internalCallback, object requestState)
    {
        var result = new Mock<IAsyncResult>();
        result.Setup(x => x.AsyncState).Returns(requestState);
        internalCallback(result.Object);
    }
}
    [Test]
    public void Callback_VerifyingWithMethodImplementation_VerifyWorks()
    {
        // arrange
        var sender = new Mock<IRequestSender>();
        sender.Setup(s => s.Send(It.IsAny<HttpWebRequest>(), It.IsAny<AsyncCallback>(), It.IsAny<object>())).Callback<HttpWebRequest, AsyncCallback, object>(RequestSenderHelpers.Send);
        // act
        sender.Object.Send(null, delegate {}, null);
        // assert
        sender.Verify(s => s.Send(It.IsAny<HttpWebRequest>(), It.IsAny<AsyncCallback>(), It.IsAny<object>()));
    }

为了避免冗长的设置,您可以将方法的设置包装在一个扩展方法中,并相应地更改您的测试:

public static class RequestSenderHelpers
{
    public static void Send(HttpWebRequest request, AsyncCallback internalCallback, object requestState)
    {
        var result = new Mock<IAsyncResult>();
        result.Setup(x => x.AsyncState).Returns(requestState);
        internalCallback(result.Object);
    }
    public static void SetupSendWithMockedAsyncResult(this Mock<IRequestSender> sender)
    {
        sender.Setup(s => s.Send(It.IsAny<HttpWebRequest>(), It.IsAny<AsyncCallback>(), It.IsAny<object>())).Callback<HttpWebRequest, AsyncCallback, object>(Send);            
    }
}
    [Test]
    public void Callback_VerifyingWithMethodImplementation_VerifyWorks()
    {
        // arrange
        var sender = new Mock<IRequestSender>();
        sender.SetupSendWithMockedAsyncResult();
        // act
        sender.Object.Send(null, delegate {}, null);
        // assert
        sender.Verify(s => s.Send(It.IsAny<HttpWebRequest>(), It.IsAny<AsyncCallback>(), It.IsAny<object>()));
    }