Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 带有Polly的单元测试HttpClient_C#_Unit Testing_Httpclient_Polly - Fatal编程技术网

C# 带有Polly的单元测试HttpClient

C# 带有Polly的单元测试HttpClient,c#,unit-testing,httpclient,polly,C#,Unit Testing,Httpclient,Polly,我想对一个HttpClient进行单元测试,它有一个PollyRetryPolicy,我想知道如何控制HTTP响应 我在客户端上使用了一个HttpMessageHandler,然后覆盖了Send Async,这非常有效,但是当我添加Polly重试策略时,我必须使用IServiceCollection创建一个HTTP客户端实例,并且无法为客户端创建HttpMessageHandler。我尝试过使用.AddHttpMessageHandler(),但这会阻止轮询重试策略,并且只触发一次 这就是我在测

我想对一个
HttpClient
进行单元测试,它有一个
Polly
RetryPolicy
,我想知道如何控制
HTTP
响应

我在客户端上使用了一个
HttpMessageHandler
,然后覆盖了Send Async,这非常有效,但是当我添加Polly重试策略时,我必须使用
IServiceCollection
创建一个HTTP客户端实例,并且无法为客户端创建
HttpMessageHandler
。我尝试过使用
.AddHttpMessageHandler()
,但这会阻止轮询重试策略,并且只触发一次

这就是我在测试中设置HTTP客户端的方式

IServiceCollection services = new ServiceCollection();

const string TestClient = "TestClient";
 
services.AddHttpClient(name: TestClient)
         .AddHttpMessageHandler()
         .SetHandlerLifetime(TimeSpan.FromMinutes(5))
         .AddPolicyHandler(KYA_GroupService.ProductMessage.ProductMessageHandler.GetRetryPolicy());

HttpClient configuredClient =
                services
                    .BuildServiceProvider()
                    .GetRequiredService<IHttpClientFactory>()
                    .CreateClient(TestClient);

public static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
    return HttpPolicyExtensions
            .HandleTransientHttpError()
            .WaitAndRetryAsync(6,
                retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
                onRetryAsync: OnRetryAsync);
}

private async static Task OnRetryAsync(DelegateResult<HttpResponseMessage> outcome, TimeSpan timespan, int retryCount, Context context)
{
    //Log result
}
IServiceCollection服务=newServiceCollection();
常量字符串TestClient=“TestClient”;
services.AddHttpClient(名称:TestClient)
.AddHttpMessageHandler()
.SetHandlerLifetime(时间跨度从分钟(5))
.AddPolicyHandler(KYA_GroupService.ProductMessage.ProductMessageHandler.GetRetryPolicy());
HttpClient配置的客户端=
服务
.BuildServiceProvider()
.GetRequiredService()
.CreateClient(TestClient);
公共静态IAsyncPolicy GetRetryPolicy()
{
返回HttpPolicyExtensions
.HandleTransientHttpError()
.WaitandertryAsync(6,
retrytry=>TimeSpan.FromSeconds(Math.Pow(2,retrytry)),
onRetryAsync:onRetryAsync);
}
私有异步静态任务OnRetryAsync(DelegateResult结果、TimeSpan TimeSpan、int retryCount、上下文)
{
//日志结果
}
然后,当我调用
\u httpClient.sendaync(httpRequestMessage)
时,这将触发请求,但它实际上创建了一个对地址的Http调用,我需要截取该请求并返回一个受控响应

我想测试该策略是否用于在请求失败时重试请求,并在请求是完整响应时完成


我的主要限制是不能在MSTest上使用Moq。

您不希望您的
HttpClient
作为单元测试的一部分发出真正的HTTP请求-这将是一个集成测试。为了避免发出真正的请求,您需要提供一个定制的
HttpMessageHandler
。您已在帖子中规定不希望使用模拟框架,因此,您可以提供一个模拟框架,而不是模拟
HttpMessageHandler

由于Polly的GitHub页面上对一个问题的评论影响很大,我调整了您的示例以调用stubbed
HttpMessageHandler
,它在第一次调用时抛出500,然后在后续请求时返回200

测试断言调用了重试处理程序,并且当执行步骤超过对HttpClient.SendAsync的调用时,结果响应的状态代码为200:

public class HttpClient_Polly_Test
{
    const string TestClient = "TestClient";
    private bool _isRetryCalled;

    [Fact]
    public async Task Given_A_Retry_Policy_Has_Been_Registered_For_A_HttpClient_When_The_HttpRequest_Fails_Then_The_Request_Is_Retried()
    {
        // Arrange 
        IServiceCollection services = new ServiceCollection();
        _isRetryCalled = false;

        services.AddHttpClient(TestClient)
            .AddPolicyHandler(GetRetryPolicy())
            .AddHttpMessageHandler(() => new StubDelegatingHandler());

        HttpClient configuredClient =
            services
                .BuildServiceProvider()
                .GetRequiredService<IHttpClientFactory>()
                .CreateClient(TestClient);

        // Act
        var result = await configuredClient.GetAsync("https://www.stackoverflow.com");

        // Assert
        Assert.True(_isRetryCalled);
        Assert.Equal(HttpStatusCode.OK, result.StatusCode);
    }

    public IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
    {
        return HttpPolicyExtensions.HandleTransientHttpError()
            .WaitAndRetryAsync(
                6,
                retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
                onRetryAsync: OnRetryAsync);
    }

    private async Task OnRetryAsync(DelegateResult<HttpResponseMessage> outcome, TimeSpan timespan, int retryCount, Context context)
    {
        //Log result
        _isRetryCalled = true;
    }
}

public class StubDelegatingHandler : DelegatingHandler
{
    private int _count = 0;

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        if (_count == 0)
        {
            _count++;
            return Task.FromResult(new HttpResponseMessage(HttpStatusCode.InternalServerError));
        }

        return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK));
    }
}
公共类HttpClient\u Polly\u测试
{
常量字符串TestClient=“TestClient”;
私人住宅被重新调用;
[事实]
给定的公共异步任务\u重试\u策略\u已注册\u HttpClient\u当\u HttpRequest\u失败时\u请求\u重试()
{
//安排
IServiceCollection服务=新的ServiceCollection();
_isRetryCalled=false;
services.AddHttpClient(TestClient)
.AddPolicyHandler(GetRetryPolicy())
.AddHttpMessageHandler(()=>new StubDelegatingHandler());
HttpClient配置的客户端=
服务
.BuildServiceProvider()
.GetRequiredService()
.CreateClient(TestClient);
//表演
var result=await configuredClient.GetAsync(“https://www.stackoverflow.com");
//断言
Assert.True(_isRetryCalled);
Assert.Equal(HttpStatusCode.OK,result.StatusCode);
}
公共IAsyncPolicy GetRetryPolicy()
{
返回HttpPolicyExtensions.HandletTransientHttpError()
.WaitAndRetryAsync(
6.
retrytry=>TimeSpan.FromSeconds(Math.Pow(2,retrytry)),
onRetryAsync:onRetryAsync);
}
私有异步任务OnRetryAsync(DelegateResult结果、TimeSpan TimeSpan、int retryCount、上下文)
{
//日志结果
_isRetryCalled=true;
}
}
公共类StubDelegatingHandler:DelegatingHandler
{
私有整数_计数=0;
受保护的覆盖任务SendAsync(HttpRequestMessage请求,
取消令牌(取消令牌)
{
如果(_count==0)
{
_计数++;
返回Task.FromResult(新的HttpResponseMessage(HttpStatusCode.InternalServerError));
}
返回Task.FromResult(新的HttpResponseMessage(HttpStatusCode.OK));
}
}

您不希望您的
HttpClient
作为单元测试的一部分发出真正的HTTP请求,这将是一个集成测试。为了避免发出真正的请求,您需要提供一个定制的
HttpMessageHandler
。您已在帖子中规定不希望使用模拟框架,因此,您可以提供一个模拟框架,而不是模拟
HttpMessageHandler

由于Polly的GitHub页面上对一个问题的评论影响很大,我调整了您的示例以调用stubbed
HttpMessageHandler
,它在第一次调用时抛出500,然后在后续请求时返回200

测试断言调用了重试处理程序,并且当执行步骤超过对HttpClient.SendAsync的调用时,结果响应的状态代码为200:

public class HttpClient_Polly_Test
{
    const string TestClient = "TestClient";
    private bool _isRetryCalled;

    [Fact]
    public async Task Given_A_Retry_Policy_Has_Been_Registered_For_A_HttpClient_When_The_HttpRequest_Fails_Then_The_Request_Is_Retried()
    {
        // Arrange 
        IServiceCollection services = new ServiceCollection();
        _isRetryCalled = false;

        services.AddHttpClient(TestClient)
            .AddPolicyHandler(GetRetryPolicy())
            .AddHttpMessageHandler(() => new StubDelegatingHandler());

        HttpClient configuredClient =
            services
                .BuildServiceProvider()
                .GetRequiredService<IHttpClientFactory>()
                .CreateClient(TestClient);

        // Act
        var result = await configuredClient.GetAsync("https://www.stackoverflow.com");

        // Assert
        Assert.True(_isRetryCalled);
        Assert.Equal(HttpStatusCode.OK, result.StatusCode);
    }

    public IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
    {
        return HttpPolicyExtensions.HandleTransientHttpError()
            .WaitAndRetryAsync(
                6,
                retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
                onRetryAsync: OnRetryAsync);
    }

    private async Task OnRetryAsync(DelegateResult<HttpResponseMessage> outcome, TimeSpan timespan, int retryCount, Context context)
    {
        //Log result
        _isRetryCalled = true;
    }
}

public class StubDelegatingHandler : DelegatingHandler
{
    private int _count = 0;

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        if (_count == 0)
        {
            _count++;
            return Task.FromResult(new HttpResponseMessage(HttpStatusCode.InternalServerError));
        }

        return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK));
    }
}
公共类HttpClient\u Polly\u测试
{
常量字符串TestClient=“TestClient”;
私人住宅被重新调用;
[事实]
给定的公共异步任务\u重试\u策略\u已注册\u HttpClient\u当\u HttpRequest\u失败时\u请求\u重试()
{
//安排
IServiceCollection服务=新的ServiceCollection();