模拟HttpRequestException以进行单元测试

时间:2016-08-26 12:42:29

标签: c# unit-testing httpclient

我有一个从网上下载大量pdf的应用程序。有时,我得到一个HttpRequestException,包含消息:将内容复制到流时出错。

所以,我正在尝试对我的代码进行单元测试以处理这种情况。我目前的下载代码是:

var request = await httpClient.GetAsync(url);

// This is where the exception would be thrown
await request.Content.ReadAsByteArrayAsync());

现在我正在尝试模拟HttpRequestException,以便我可以对上面的代码进行单元测试,但我不知道该怎么做。有人可以帮忙吗?

提前致谢!

2 个答案:

答案 0 :(得分:2)

这里的关键是创建一个抛出异常的HttpContent

public class ExceptionThrowingContent : HttpContent
{
    private readonly Exception exception;
    public ExceptionThrowingContent(Exception exception)
    {
        this.exception = exception;
    }

    protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
    {
        return Task.FromException(exception);
    }

    protected override bool TryComputeLength(out long length)
    {
        length = 0L;
        return false;
    }
}

完成后,您可以使用我自己的mockhttp之类的东西来模拟请求:

var handler = new MockHttpMessageHandler();
handler.When("http://tempuri.org/url")
    .Respond(new ExceptionThrowingContent(ex));

var mockClient = new HttpClient(handler);

// pass mockHandler to your component

现在,如果您的组件在发出请求时传入HttpCompletionOption.ResponseHeadersRead,则会在await Content.ReadAsByteArrayAsync()处抛出异常。如果没有,HttpClient将尝试缓冲响应,以便在await HttpClient.GetAsync()抛出异常。

如果响应 被缓冲,那么在ReadAsByteArrayAsync抛出异常实际上是“不可能的”,因此尝试模拟它是没有意义的。 (OutOfMemoryException之外的“不可能”)

答案 1 :(得分:1)

使用MockHttp可以轻松地设置HttpClient测试,您可以返回自定义的HttpContent,在此示例中会抛出HttpRequestException

[TestMethod]
[ExpectedException(typeof(HttpRequestException))]
public async Task Test()
{
    var content = new ContentWithException();
    var mockHttp = new MockHttpMessageHandler();
    mockHttp.Expect("http://localhost/mypdfDownload").Respond(content);

    var client = new HttpClient(mockHttp);
    var response = await client.GetAsync("http://localhost/mypdfDownload");

    await response.Content.ReadAsByteArrayAsync();
}

private class ContentWithException : HttpContent
{
    protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
    {
        throw new HttpRequestException();
    }

    protected override bool TryComputeLength(out long length)
    {
        length = 0;
        return false;
    }
}