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

Vaj*_*jda 6 c# moq mocking

情况就是这样.我有异步调用所以我需要为此进行Mid tier才能测试它.

request.BeginGetResponse(new AsyncCallback(LoginCallback), requestState);
Run Code Online (Sandbox Code Playgroud)

因此,为了能够在没有实际请求的情况下测试它,我创建了可以模拟的界面.

public interface IRequestSender
    {
        void Send(HttpWebRequest request, AsyncCallback internalCallback, object requestState);
    }
Run Code Online (Sandbox Code Playgroud)

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

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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

我现在可以在单元测试中轻松创建模拟对象并使用它.但是当我创造

var sender = new Mock<RequestSenderMock>();
Run Code Online (Sandbox Code Playgroud)

我无法验证此对象的通话计数.

sender.Verify(x => x.Send(It.IsAny<HttpWebRequest>(), It.IsAny<AsyncCallback>(), It.IsAny<object>()), Times.Once());
Run Code Online (Sandbox Code Playgroud)

它说我的方法需要是虚拟的.有没有办法在不使我的方法虚拟的情况下做到这一点?如果我能在某种程度上指定使用接口时的方法实现,那将是最好的.

var sender = new Mock<IRequestSender>();
Run Code Online (Sandbox Code Playgroud)

并以某种方式使用Setup方法或其他一些方法在这个模拟对象上进行实现.比我简单地删除我的模拟课程.这可能吗?你有什么建议?

Mar*_*ius 10

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

例:

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>()));
    }
Run Code Online (Sandbox Code Playgroud)

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

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>()));
    }
Run Code Online (Sandbox Code Playgroud)