c# - 使用 Moq 将参数修改为 stub void 方法

标签 c# moq void

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

这是发送请求的代码:

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 后,它包含我在测试中设置的 stub 值。

但是,在执行回调并将控制返回到我的应用程序代码后,我的 method 变量仍然具有我在上面的步骤 1 中看到的旧值,这会在尝试时导致空引用异常阅读 method.ResponseBodyAsStream

我正在尝试做的事情是否可以实现?如果是这样,如何?谢谢!

最佳答案

我已经通过 vis mocking 复制了您的设置,但没有发现任何问题:

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 上向我显示它)。你的问题可能在那里吗?

顺便说一句,您尝试做的事情几乎肯定可以通过最小起订量实现。

关于c# - 使用 Moq 将参数修改为 stub void 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9281708/

相关文章:

c# - 更新 UI 元素时锁定 Parallel Linq

c# - if条件内的sql select语句

vb.net - 如何使用最小起订量发起事件?

asp.net-mvc - 如何使用 Moq 模拟 ActionExecutingContext?

c - 如果指针可以转换为任何类型(在 c 中),为什么要 void pointer?

c# - 这种对泛型的滥用如何不模棱两可/在编译器中触发错误

c# - 是否可以在传递给泛型方法的类型上调用方法?

unit-testing - 使用 Moq 模拟返回值的存储库

java - 即使我可以在两者上获得相同的输出,void 和 return 之间有什么区别?

c++ - 函数 C++ 中的参数