我遇到了一场完美 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
操作被执行时,我观察到两件事,这两件事都是我所期望的:
- 传入的
IHttpMethod
(m
) 具有我期望的属性。 - 将模拟对象分配给
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/