使用 Moq 修改存根 void 方法的参数

发布于 2025-01-06 03:05:45 字数 1768 浏览 1 评论 0原文

我遇到了一场完美风暴,导致我无法测试课程。该类是一个 RestClient ,它包装了一个内部 HttpClient (我无法修改)。 HttpClient 上的 ExecuteMethod 方法无效。它接受 IHttpMethod,并根据服务器的响应修改此对象。我想模拟 ExecuteMethod ,以便它为我修改 IHttpMethod 。我正在尝试使用回调来实现此目的,但它不起作用。

这是发送请求的代码:

var httpClient = this.httpClientFactory.CreateHttpClient();
httpClient.ExecuteMethod(method);

var response = this.GetResourceResponse<T>(method.ResponseBodyAsStream.AsString());
response.ResponseHeaders = method.ResponseHeaders;
response.Status = method.StatusCode.ToString();
response.StatusCode = (int)method.StatusCode;

return response;

这是我的模拟尝试:

var mockHttpMethod = new Mock<IHttpMethod>();
mockHttpMethod.Setup(m => m.ResponseBodyAsStream).Returns(new MemoryStream(Encoding.UTF8.GetBytes("foo")));

var modifyHttpMethod = new Action<IHttpMethod>(m =>
{
    m = mockHttpMethod.Object;
});

var mockHttpClient = new Mock<IHttpClient>();
mockHttpClient.Setup(c => c.ExecuteMethod(It.IsAny<IHttpMethod>()))
    .Callback<IHttpMethod>(modifyHttpMethod);

var mockHttpClientFactory = new Mock<ILegalHoldHttpClientFactory>();
mockHttpClientFactory.Setup(f => f.CreateHttpClient()).Returns(mockHttpClient.Object);

var restClient = new RestClient(mockHttpClientFactory.Object);

当执行 modifyHttpMethod 操作时,我观察到两件事,这两件事都是我所期望的:

  1. 传入的 IHttpMethod (m) 具有我期望它具有的属性。
  2. 将模拟对象分配给 m 后,它包含我在测试中设置的存根值。

但是,在执行回调并将控制权返回到我的应用程序代码后,我的 method 变量仍然具有我在上面步骤 1 中看到的旧值,这会在尝试读取 <代码>方法.ResponseBodyAsStream。

我想做的事情可以实现吗?如果是这样,怎么办?谢谢!

I have a bit of a perfect storm that's preventing me from testing a class. The class is a RestClient that's wrapping an in-house HttpClient (which I cannot modify). The ExecuteMethod method on the HttpClient is void. It accepts an IHttpMethod, and it modifies this object based on the response from the server. I want to mock out ExecuteMethod so that it modifies the IHttpMethod for me. I'm trying to use Callback to achieve this, but it's not working.

Here's the code that sends the request:

var httpClient = this.httpClientFactory.CreateHttpClient();
httpClient.ExecuteMethod(method);

var response = this.GetResourceResponse<T>(method.ResponseBodyAsStream.AsString());
response.ResponseHeaders = method.ResponseHeaders;
response.Status = method.StatusCode.ToString();
response.StatusCode = (int)method.StatusCode;

return response;

And here's my attempt at mocking:

var mockHttpMethod = new Mock<IHttpMethod>();
mockHttpMethod.Setup(m => m.ResponseBodyAsStream).Returns(new MemoryStream(Encoding.UTF8.GetBytes("foo")));

var modifyHttpMethod = new Action<IHttpMethod>(m =>
{
    m = mockHttpMethod.Object;
});

var mockHttpClient = new Mock<IHttpClient>();
mockHttpClient.Setup(c => c.ExecuteMethod(It.IsAny<IHttpMethod>()))
    .Callback<IHttpMethod>(modifyHttpMethod);

var mockHttpClientFactory = new Mock<ILegalHoldHttpClientFactory>();
mockHttpClientFactory.Setup(f => f.CreateHttpClient()).Returns(mockHttpClient.Object);

var restClient = new RestClient(mockHttpClientFactory.Object);

When the modifyHttpMethod action is executed, I observe two things, both of which I expect:

  1. The incoming IHttpMethod (m) has the properties I expect it to have.
  2. After assigning the mock object to m, it contains the stubbed values that I setup in my test.

However, after the callback is executed and control is returned to my application code, my method variable still has its old values that I saw in step 1 above, which causes a null reference exception when trying to read method.ResponseBodyAsStream.

Is what I'm trying to do even achievable? If so, how? Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

赴月观长安 2025-01-13 03:05:45

我已经通过 vis 模拟复制了您的设置,但找不到任何问题:

public interface IHttpMethod
{
    MemoryStream ResponseBodyAsStream { get; set; }
}

public interface IHttpClient
{
    void ExecuteMethod(IHttpMethod method);
}

public class HttpClient : IHttpClient
{

    #region IHttpClient Members

    public void ExecuteMethod(IHttpMethod method)
    {

    }

    #endregion
}

public class Factory
{
    public virtual IHttpClient CreateHttpClient()
    {
        return new HttpClient();
    }
}

public class ClassUnderTest
{
    private readonly Factory _factory;

    public ClassUnderTest(Factory factory)
    {
        _factory = factory;
    }

    public string GetResponseAsString(IHttpMethod method)
    {
        var myClient = _factory.CreateHttpClient();
        myClient.ExecuteMethod(method);

        return method.ResponseBodyAsStream.ToString();
    }
}

[TestClass]
public class ScratchPadTest
{
    [TestMethod]
    public void SampleTest()
    {
        var mockHttpMethod = new Mock<IHttpMethod>();
        mockHttpMethod.Setup(x => x.ResponseBodyAsStream).Returns(new MemoryStream(Encoding.UTF8.GetBytes("foo")));

        var modifyHttpMethod = new Action<IHttpMethod>(m =>
        {
            m = mockHttpMethod.Object;
        });

        var mockHttpClient = new Mock<IHttpClient>();
        mockHttpClient.Setup(c => c.ExecuteMethod(It.IsAny<IHttpMethod>())).Callback<IHttpMethod>(modifyHttpMethod);

        var myFactoryStub = new Mock<Factory>();
        myFactoryStub.Setup(f => f.CreateHttpClient()).Returns(mockHttpClient.Object);

        var myCut = new ClassUnderTest(myFactoryStub.Object);

        Assert.IsNotNull(myCut.GetResponseAsString(mockHttpMethod.Object));
    }

}

该测试通过,意味着内存流不为空(否则会生成异常)。我能看到的唯一 X 因素是你的 AsString() 扩展方法(我假设这是一个扩展方法,因为智能感知不会在 MemoryStream 上向我显示它)。你的问题会在那里吗?

顺便说一句,您想要做的事情几乎肯定可以通过 Moq 实现。

I've replicated your setup vis a vis mocking, and can't find any issues with it:

public interface IHttpMethod
{
    MemoryStream ResponseBodyAsStream { get; set; }
}

public interface IHttpClient
{
    void ExecuteMethod(IHttpMethod method);
}

public class HttpClient : IHttpClient
{

    #region IHttpClient Members

    public void ExecuteMethod(IHttpMethod method)
    {

    }

    #endregion
}

public class Factory
{
    public virtual IHttpClient CreateHttpClient()
    {
        return new HttpClient();
    }
}

public class ClassUnderTest
{
    private readonly Factory _factory;

    public ClassUnderTest(Factory factory)
    {
        _factory = factory;
    }

    public string GetResponseAsString(IHttpMethod method)
    {
        var myClient = _factory.CreateHttpClient();
        myClient.ExecuteMethod(method);

        return method.ResponseBodyAsStream.ToString();
    }
}

[TestClass]
public class ScratchPadTest
{
    [TestMethod]
    public void SampleTest()
    {
        var mockHttpMethod = new Mock<IHttpMethod>();
        mockHttpMethod.Setup(x => x.ResponseBodyAsStream).Returns(new MemoryStream(Encoding.UTF8.GetBytes("foo")));

        var modifyHttpMethod = new Action<IHttpMethod>(m =>
        {
            m = mockHttpMethod.Object;
        });

        var mockHttpClient = new Mock<IHttpClient>();
        mockHttpClient.Setup(c => c.ExecuteMethod(It.IsAny<IHttpMethod>())).Callback<IHttpMethod>(modifyHttpMethod);

        var myFactoryStub = new Mock<Factory>();
        myFactoryStub.Setup(f => f.CreateHttpClient()).Returns(mockHttpClient.Object);

        var myCut = new ClassUnderTest(myFactoryStub.Object);

        Assert.IsNotNull(myCut.GetResponseAsString(mockHttpMethod.Object));
    }

}

That test passes, meaning that the memory stream is not null (otherwise an exception would be generated). The only X factor that I can see is your AsString() extension method (I'm assuming that's an extension method as intellisense doesn't show it to me on MemoryStream). Could your problem be in there?

And, by the way, what you're trying to do is almost certainly achievable with Moq.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文