Test Polly retry polly configured via Startup.ConfigureServices() with ASP.NET Core API





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







0















I want to find out how Polly retry polly configured via Startup.ConfigureServices() can be tested.



ConfigureServices



Polly policy is configured within it



public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient<IHttpClientService, HttpClientService>()
.SetWaitAndRetryPolicy1();

}
}


Below is the Polly policy:



 public static class IServiceCollectionExtension
{

public static void SetWaitAndRetryPolicy1(this IHttpClientBuilder clientBuilder)
{
clientBuilder.AddPolicyHandler((service, request) =>
HttpPolicyExtensions.HandleTransientHttpError()
.WaitAndRetryAsync(3,
retryCount => TimeSpan.FromSeconds(Math.Pow(2, retryCount)),
onRetry: (outcome, timespan, retryCount, context) =>
{
service.GetService<ILog>().Error("Delaying for {delay}ms, then making retry {retry}.",
timespan.TotalMilliseconds, retryCount);
}
)

);
}
}


Below is what I tried:



Integration test



The Polly policy is configured within the test.



  public class RetryPolicyTests : IClassFixture<WebApplicationFactory<Startup>>
{
private readonly WebApplicationFactory<Startup> _factory;

public RetryPolicyTests(WebApplicationFactory<Startup> factory)
{
_factory = factory;
}

[Theory]
[InlineData("http://localhost:1234/api/v1/car/")]
public async Task Test3(string url)
{
// Arrange
var client = _factory.WithWebHostBuilder(whb =>
{
whb.ConfigureServices((bc, sc) =>
{
sc.AddOptions();
sc.AddHttpClient("test")
.SetWaitAndRetryPolicy1(); //Test the Polly policy
sc.BuildServiceProvider();
});
})
.CreateClient(); //cannot get a named or typed HttpClient

// Act
var body = "{}";
using (var content = new StringContent(body, Encoding.UTF8, "application/json"))
{

var response = await client.PostAsync(url, content);



}

//Assert: somewhy assert it
}
}
}


The problem is that



I cannot retrieve the HttpClient that has been configured with the Polly polly. Because WebApplicationFactory.CreateClient() has no overloads that returns a named or typed HttpClient:



Any idea?



Is there a better way to testing it?



ASPS.NET Core API 2.2










share|improve this question































    0















    I want to find out how Polly retry polly configured via Startup.ConfigureServices() can be tested.



    ConfigureServices



    Polly policy is configured within it



    public class Startup
    {
    public void ConfigureServices(IServiceCollection services)
    {
    services.AddHttpClient<IHttpClientService, HttpClientService>()
    .SetWaitAndRetryPolicy1();

    }
    }


    Below is the Polly policy:



     public static class IServiceCollectionExtension
    {

    public static void SetWaitAndRetryPolicy1(this IHttpClientBuilder clientBuilder)
    {
    clientBuilder.AddPolicyHandler((service, request) =>
    HttpPolicyExtensions.HandleTransientHttpError()
    .WaitAndRetryAsync(3,
    retryCount => TimeSpan.FromSeconds(Math.Pow(2, retryCount)),
    onRetry: (outcome, timespan, retryCount, context) =>
    {
    service.GetService<ILog>().Error("Delaying for {delay}ms, then making retry {retry}.",
    timespan.TotalMilliseconds, retryCount);
    }
    )

    );
    }
    }


    Below is what I tried:



    Integration test



    The Polly policy is configured within the test.



      public class RetryPolicyTests : IClassFixture<WebApplicationFactory<Startup>>
    {
    private readonly WebApplicationFactory<Startup> _factory;

    public RetryPolicyTests(WebApplicationFactory<Startup> factory)
    {
    _factory = factory;
    }

    [Theory]
    [InlineData("http://localhost:1234/api/v1/car/")]
    public async Task Test3(string url)
    {
    // Arrange
    var client = _factory.WithWebHostBuilder(whb =>
    {
    whb.ConfigureServices((bc, sc) =>
    {
    sc.AddOptions();
    sc.AddHttpClient("test")
    .SetWaitAndRetryPolicy1(); //Test the Polly policy
    sc.BuildServiceProvider();
    });
    })
    .CreateClient(); //cannot get a named or typed HttpClient

    // Act
    var body = "{}";
    using (var content = new StringContent(body, Encoding.UTF8, "application/json"))
    {

    var response = await client.PostAsync(url, content);



    }

    //Assert: somewhy assert it
    }
    }
    }


    The problem is that



    I cannot retrieve the HttpClient that has been configured with the Polly polly. Because WebApplicationFactory.CreateClient() has no overloads that returns a named or typed HttpClient:



    Any idea?



    Is there a better way to testing it?



    ASPS.NET Core API 2.2










    share|improve this question



























      0












      0








      0


      0






      I want to find out how Polly retry polly configured via Startup.ConfigureServices() can be tested.



      ConfigureServices



      Polly policy is configured within it



      public class Startup
      {
      public void ConfigureServices(IServiceCollection services)
      {
      services.AddHttpClient<IHttpClientService, HttpClientService>()
      .SetWaitAndRetryPolicy1();

      }
      }


      Below is the Polly policy:



       public static class IServiceCollectionExtension
      {

      public static void SetWaitAndRetryPolicy1(this IHttpClientBuilder clientBuilder)
      {
      clientBuilder.AddPolicyHandler((service, request) =>
      HttpPolicyExtensions.HandleTransientHttpError()
      .WaitAndRetryAsync(3,
      retryCount => TimeSpan.FromSeconds(Math.Pow(2, retryCount)),
      onRetry: (outcome, timespan, retryCount, context) =>
      {
      service.GetService<ILog>().Error("Delaying for {delay}ms, then making retry {retry}.",
      timespan.TotalMilliseconds, retryCount);
      }
      )

      );
      }
      }


      Below is what I tried:



      Integration test



      The Polly policy is configured within the test.



        public class RetryPolicyTests : IClassFixture<WebApplicationFactory<Startup>>
      {
      private readonly WebApplicationFactory<Startup> _factory;

      public RetryPolicyTests(WebApplicationFactory<Startup> factory)
      {
      _factory = factory;
      }

      [Theory]
      [InlineData("http://localhost:1234/api/v1/car/")]
      public async Task Test3(string url)
      {
      // Arrange
      var client = _factory.WithWebHostBuilder(whb =>
      {
      whb.ConfigureServices((bc, sc) =>
      {
      sc.AddOptions();
      sc.AddHttpClient("test")
      .SetWaitAndRetryPolicy1(); //Test the Polly policy
      sc.BuildServiceProvider();
      });
      })
      .CreateClient(); //cannot get a named or typed HttpClient

      // Act
      var body = "{}";
      using (var content = new StringContent(body, Encoding.UTF8, "application/json"))
      {

      var response = await client.PostAsync(url, content);



      }

      //Assert: somewhy assert it
      }
      }
      }


      The problem is that



      I cannot retrieve the HttpClient that has been configured with the Polly polly. Because WebApplicationFactory.CreateClient() has no overloads that returns a named or typed HttpClient:



      Any idea?



      Is there a better way to testing it?



      ASPS.NET Core API 2.2










      share|improve this question
















      I want to find out how Polly retry polly configured via Startup.ConfigureServices() can be tested.



      ConfigureServices



      Polly policy is configured within it



      public class Startup
      {
      public void ConfigureServices(IServiceCollection services)
      {
      services.AddHttpClient<IHttpClientService, HttpClientService>()
      .SetWaitAndRetryPolicy1();

      }
      }


      Below is the Polly policy:



       public static class IServiceCollectionExtension
      {

      public static void SetWaitAndRetryPolicy1(this IHttpClientBuilder clientBuilder)
      {
      clientBuilder.AddPolicyHandler((service, request) =>
      HttpPolicyExtensions.HandleTransientHttpError()
      .WaitAndRetryAsync(3,
      retryCount => TimeSpan.FromSeconds(Math.Pow(2, retryCount)),
      onRetry: (outcome, timespan, retryCount, context) =>
      {
      service.GetService<ILog>().Error("Delaying for {delay}ms, then making retry {retry}.",
      timespan.TotalMilliseconds, retryCount);
      }
      )

      );
      }
      }


      Below is what I tried:



      Integration test



      The Polly policy is configured within the test.



        public class RetryPolicyTests : IClassFixture<WebApplicationFactory<Startup>>
      {
      private readonly WebApplicationFactory<Startup> _factory;

      public RetryPolicyTests(WebApplicationFactory<Startup> factory)
      {
      _factory = factory;
      }

      [Theory]
      [InlineData("http://localhost:1234/api/v1/car/")]
      public async Task Test3(string url)
      {
      // Arrange
      var client = _factory.WithWebHostBuilder(whb =>
      {
      whb.ConfigureServices((bc, sc) =>
      {
      sc.AddOptions();
      sc.AddHttpClient("test")
      .SetWaitAndRetryPolicy1(); //Test the Polly policy
      sc.BuildServiceProvider();
      });
      })
      .CreateClient(); //cannot get a named or typed HttpClient

      // Act
      var body = "{}";
      using (var content = new StringContent(body, Encoding.UTF8, "application/json"))
      {

      var response = await client.PostAsync(url, content);



      }

      //Assert: somewhy assert it
      }
      }
      }


      The problem is that



      I cannot retrieve the HttpClient that has been configured with the Polly polly. Because WebApplicationFactory.CreateClient() has no overloads that returns a named or typed HttpClient:



      Any idea?



      Is there a better way to testing it?



      ASPS.NET Core API 2.2







      c# asp.net-core .net-core asp.net-core-webapi polly






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jan 4 at 15:28







      Pingpong

















      asked Jan 3 at 21:37









      PingpongPingpong

      2,426124499




      2,426124499
























          1 Answer
          1






          active

          oldest

          votes


















          1














          To modify your posted code minimally to obtain the named or typed HttpClient configured on HttpClientFactory, build the IServiceProvider, obtain the IHttpClientFactory and then obtain the configured client from IHttpClientFactory.



          var configuredClient = sc.BuildServiceProvider()
          .GetRequiredService<IHttpClientFactory>()
          .CreateClient("test");


          Many people consider the use of IServiceProvider like this to be a service-locator anti-pattern in production code; perhaps it is ok here in a test, to pull the specific item you want to unit-test out of the default app configuration. However, there are also shorter ways for a test to get a sample HttpClient configured on HttpClientFactory, without using a full WebApplicationFactory (see last part of answer).





          For a full end-to-end integration test, testing how your app uses the configured policy, using WebApplicationFactory to exercise some endpoint of your app like http://localhost:1234/api/v1/car/:



          You could - within the integration test - use a tool like Mountebank for .NET or HttpClientInterception to stub out the calls that the configured HttpClient makes, so that those calls return errors which you expect the policy to handle.



          You could use the ability of WebHostBuilder.ConfigureServices(...) to modify the normal startup of your app, to make it easy to assert something to prove the policy was called. For example, you could configure a mock/fake ILog implementation, and assert that the ILog.Error(...) call in your onRetry delegate takes place.





          For the shortest-possible, self-contained unit test to test a Polly policy configured on a given HttpClient configuration on HttpClientFactory, you could use a code pattern like below. This only uses IHttpClientFactory and the standard Microsoft DI infrastructure; no web host from ASP.NET.



          public class HttpClientFactory_Polly_Policy_Test
          {
          [Fact]
          public async Task Given_a_retry_policy_configured_on_a_named_client_When_call_via_the_named_client_Then_the_policy_is_used()
          {
          // Given / Arrange
          IServiceCollection services = new ServiceCollection();

          bool retryCalled = false;

          HttpStatusCode codeHandledByPolicy = HttpStatusCode.InternalServerError;

          const string TestClient = "TestClient";
          services.AddHttpClient(TestClient)
          .AddPolicyHandler(HttpPolicyExtensions.HandleTransientHttpError()
          .RetryAsync(3, onRetry: (_, __) => retryCalled = true))
          .AddHttpMessageHandler(() => new StubDelegatingHandler(codeHandledByPolicy));

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

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

          // Then / Assert
          Assert.Equal(codeHandledByPolicy, result.StatusCode);
          Assert.True(retryCalled);
          }

          }

          public class StubDelegatingHandler : DelegatingHandler
          {
          private readonly HttpStatusCode stubHttpStatusCode;
          public StubDelegatingHandler(HttpStatusCode stubHttpStatusCode) => this.stubHttpStatusCode = stubHttpStatusCode;
          protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) => Task.FromResult(new HttpResponseMessage(stubHttpStatusCode));
          }


          If the declarations of policies are pulled out to methods (like SetWaitAndRetryPolicy1() in your posted code), an approach like above provides a more unit-test-focused way to test them.






          share|improve this answer


























          • This is a shortened version of a longer post (more information about the end-to-end integration approach particularly), at; github.com/App-vNext/Polly/issues/555

            – mountain traveller
            Jan 4 at 23:40












          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54030145%2ftest-polly-retry-polly-configured-via-startup-configureservices-with-asp-net-c%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1














          To modify your posted code minimally to obtain the named or typed HttpClient configured on HttpClientFactory, build the IServiceProvider, obtain the IHttpClientFactory and then obtain the configured client from IHttpClientFactory.



          var configuredClient = sc.BuildServiceProvider()
          .GetRequiredService<IHttpClientFactory>()
          .CreateClient("test");


          Many people consider the use of IServiceProvider like this to be a service-locator anti-pattern in production code; perhaps it is ok here in a test, to pull the specific item you want to unit-test out of the default app configuration. However, there are also shorter ways for a test to get a sample HttpClient configured on HttpClientFactory, without using a full WebApplicationFactory (see last part of answer).





          For a full end-to-end integration test, testing how your app uses the configured policy, using WebApplicationFactory to exercise some endpoint of your app like http://localhost:1234/api/v1/car/:



          You could - within the integration test - use a tool like Mountebank for .NET or HttpClientInterception to stub out the calls that the configured HttpClient makes, so that those calls return errors which you expect the policy to handle.



          You could use the ability of WebHostBuilder.ConfigureServices(...) to modify the normal startup of your app, to make it easy to assert something to prove the policy was called. For example, you could configure a mock/fake ILog implementation, and assert that the ILog.Error(...) call in your onRetry delegate takes place.





          For the shortest-possible, self-contained unit test to test a Polly policy configured on a given HttpClient configuration on HttpClientFactory, you could use a code pattern like below. This only uses IHttpClientFactory and the standard Microsoft DI infrastructure; no web host from ASP.NET.



          public class HttpClientFactory_Polly_Policy_Test
          {
          [Fact]
          public async Task Given_a_retry_policy_configured_on_a_named_client_When_call_via_the_named_client_Then_the_policy_is_used()
          {
          // Given / Arrange
          IServiceCollection services = new ServiceCollection();

          bool retryCalled = false;

          HttpStatusCode codeHandledByPolicy = HttpStatusCode.InternalServerError;

          const string TestClient = "TestClient";
          services.AddHttpClient(TestClient)
          .AddPolicyHandler(HttpPolicyExtensions.HandleTransientHttpError()
          .RetryAsync(3, onRetry: (_, __) => retryCalled = true))
          .AddHttpMessageHandler(() => new StubDelegatingHandler(codeHandledByPolicy));

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

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

          // Then / Assert
          Assert.Equal(codeHandledByPolicy, result.StatusCode);
          Assert.True(retryCalled);
          }

          }

          public class StubDelegatingHandler : DelegatingHandler
          {
          private readonly HttpStatusCode stubHttpStatusCode;
          public StubDelegatingHandler(HttpStatusCode stubHttpStatusCode) => this.stubHttpStatusCode = stubHttpStatusCode;
          protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) => Task.FromResult(new HttpResponseMessage(stubHttpStatusCode));
          }


          If the declarations of policies are pulled out to methods (like SetWaitAndRetryPolicy1() in your posted code), an approach like above provides a more unit-test-focused way to test them.






          share|improve this answer


























          • This is a shortened version of a longer post (more information about the end-to-end integration approach particularly), at; github.com/App-vNext/Polly/issues/555

            – mountain traveller
            Jan 4 at 23:40
















          1














          To modify your posted code minimally to obtain the named or typed HttpClient configured on HttpClientFactory, build the IServiceProvider, obtain the IHttpClientFactory and then obtain the configured client from IHttpClientFactory.



          var configuredClient = sc.BuildServiceProvider()
          .GetRequiredService<IHttpClientFactory>()
          .CreateClient("test");


          Many people consider the use of IServiceProvider like this to be a service-locator anti-pattern in production code; perhaps it is ok here in a test, to pull the specific item you want to unit-test out of the default app configuration. However, there are also shorter ways for a test to get a sample HttpClient configured on HttpClientFactory, without using a full WebApplicationFactory (see last part of answer).





          For a full end-to-end integration test, testing how your app uses the configured policy, using WebApplicationFactory to exercise some endpoint of your app like http://localhost:1234/api/v1/car/:



          You could - within the integration test - use a tool like Mountebank for .NET or HttpClientInterception to stub out the calls that the configured HttpClient makes, so that those calls return errors which you expect the policy to handle.



          You could use the ability of WebHostBuilder.ConfigureServices(...) to modify the normal startup of your app, to make it easy to assert something to prove the policy was called. For example, you could configure a mock/fake ILog implementation, and assert that the ILog.Error(...) call in your onRetry delegate takes place.





          For the shortest-possible, self-contained unit test to test a Polly policy configured on a given HttpClient configuration on HttpClientFactory, you could use a code pattern like below. This only uses IHttpClientFactory and the standard Microsoft DI infrastructure; no web host from ASP.NET.



          public class HttpClientFactory_Polly_Policy_Test
          {
          [Fact]
          public async Task Given_a_retry_policy_configured_on_a_named_client_When_call_via_the_named_client_Then_the_policy_is_used()
          {
          // Given / Arrange
          IServiceCollection services = new ServiceCollection();

          bool retryCalled = false;

          HttpStatusCode codeHandledByPolicy = HttpStatusCode.InternalServerError;

          const string TestClient = "TestClient";
          services.AddHttpClient(TestClient)
          .AddPolicyHandler(HttpPolicyExtensions.HandleTransientHttpError()
          .RetryAsync(3, onRetry: (_, __) => retryCalled = true))
          .AddHttpMessageHandler(() => new StubDelegatingHandler(codeHandledByPolicy));

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

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

          // Then / Assert
          Assert.Equal(codeHandledByPolicy, result.StatusCode);
          Assert.True(retryCalled);
          }

          }

          public class StubDelegatingHandler : DelegatingHandler
          {
          private readonly HttpStatusCode stubHttpStatusCode;
          public StubDelegatingHandler(HttpStatusCode stubHttpStatusCode) => this.stubHttpStatusCode = stubHttpStatusCode;
          protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) => Task.FromResult(new HttpResponseMessage(stubHttpStatusCode));
          }


          If the declarations of policies are pulled out to methods (like SetWaitAndRetryPolicy1() in your posted code), an approach like above provides a more unit-test-focused way to test them.






          share|improve this answer


























          • This is a shortened version of a longer post (more information about the end-to-end integration approach particularly), at; github.com/App-vNext/Polly/issues/555

            – mountain traveller
            Jan 4 at 23:40














          1












          1








          1







          To modify your posted code minimally to obtain the named or typed HttpClient configured on HttpClientFactory, build the IServiceProvider, obtain the IHttpClientFactory and then obtain the configured client from IHttpClientFactory.



          var configuredClient = sc.BuildServiceProvider()
          .GetRequiredService<IHttpClientFactory>()
          .CreateClient("test");


          Many people consider the use of IServiceProvider like this to be a service-locator anti-pattern in production code; perhaps it is ok here in a test, to pull the specific item you want to unit-test out of the default app configuration. However, there are also shorter ways for a test to get a sample HttpClient configured on HttpClientFactory, without using a full WebApplicationFactory (see last part of answer).





          For a full end-to-end integration test, testing how your app uses the configured policy, using WebApplicationFactory to exercise some endpoint of your app like http://localhost:1234/api/v1/car/:



          You could - within the integration test - use a tool like Mountebank for .NET or HttpClientInterception to stub out the calls that the configured HttpClient makes, so that those calls return errors which you expect the policy to handle.



          You could use the ability of WebHostBuilder.ConfigureServices(...) to modify the normal startup of your app, to make it easy to assert something to prove the policy was called. For example, you could configure a mock/fake ILog implementation, and assert that the ILog.Error(...) call in your onRetry delegate takes place.





          For the shortest-possible, self-contained unit test to test a Polly policy configured on a given HttpClient configuration on HttpClientFactory, you could use a code pattern like below. This only uses IHttpClientFactory and the standard Microsoft DI infrastructure; no web host from ASP.NET.



          public class HttpClientFactory_Polly_Policy_Test
          {
          [Fact]
          public async Task Given_a_retry_policy_configured_on_a_named_client_When_call_via_the_named_client_Then_the_policy_is_used()
          {
          // Given / Arrange
          IServiceCollection services = new ServiceCollection();

          bool retryCalled = false;

          HttpStatusCode codeHandledByPolicy = HttpStatusCode.InternalServerError;

          const string TestClient = "TestClient";
          services.AddHttpClient(TestClient)
          .AddPolicyHandler(HttpPolicyExtensions.HandleTransientHttpError()
          .RetryAsync(3, onRetry: (_, __) => retryCalled = true))
          .AddHttpMessageHandler(() => new StubDelegatingHandler(codeHandledByPolicy));

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

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

          // Then / Assert
          Assert.Equal(codeHandledByPolicy, result.StatusCode);
          Assert.True(retryCalled);
          }

          }

          public class StubDelegatingHandler : DelegatingHandler
          {
          private readonly HttpStatusCode stubHttpStatusCode;
          public StubDelegatingHandler(HttpStatusCode stubHttpStatusCode) => this.stubHttpStatusCode = stubHttpStatusCode;
          protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) => Task.FromResult(new HttpResponseMessage(stubHttpStatusCode));
          }


          If the declarations of policies are pulled out to methods (like SetWaitAndRetryPolicy1() in your posted code), an approach like above provides a more unit-test-focused way to test them.






          share|improve this answer















          To modify your posted code minimally to obtain the named or typed HttpClient configured on HttpClientFactory, build the IServiceProvider, obtain the IHttpClientFactory and then obtain the configured client from IHttpClientFactory.



          var configuredClient = sc.BuildServiceProvider()
          .GetRequiredService<IHttpClientFactory>()
          .CreateClient("test");


          Many people consider the use of IServiceProvider like this to be a service-locator anti-pattern in production code; perhaps it is ok here in a test, to pull the specific item you want to unit-test out of the default app configuration. However, there are also shorter ways for a test to get a sample HttpClient configured on HttpClientFactory, without using a full WebApplicationFactory (see last part of answer).





          For a full end-to-end integration test, testing how your app uses the configured policy, using WebApplicationFactory to exercise some endpoint of your app like http://localhost:1234/api/v1/car/:



          You could - within the integration test - use a tool like Mountebank for .NET or HttpClientInterception to stub out the calls that the configured HttpClient makes, so that those calls return errors which you expect the policy to handle.



          You could use the ability of WebHostBuilder.ConfigureServices(...) to modify the normal startup of your app, to make it easy to assert something to prove the policy was called. For example, you could configure a mock/fake ILog implementation, and assert that the ILog.Error(...) call in your onRetry delegate takes place.





          For the shortest-possible, self-contained unit test to test a Polly policy configured on a given HttpClient configuration on HttpClientFactory, you could use a code pattern like below. This only uses IHttpClientFactory and the standard Microsoft DI infrastructure; no web host from ASP.NET.



          public class HttpClientFactory_Polly_Policy_Test
          {
          [Fact]
          public async Task Given_a_retry_policy_configured_on_a_named_client_When_call_via_the_named_client_Then_the_policy_is_used()
          {
          // Given / Arrange
          IServiceCollection services = new ServiceCollection();

          bool retryCalled = false;

          HttpStatusCode codeHandledByPolicy = HttpStatusCode.InternalServerError;

          const string TestClient = "TestClient";
          services.AddHttpClient(TestClient)
          .AddPolicyHandler(HttpPolicyExtensions.HandleTransientHttpError()
          .RetryAsync(3, onRetry: (_, __) => retryCalled = true))
          .AddHttpMessageHandler(() => new StubDelegatingHandler(codeHandledByPolicy));

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

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

          // Then / Assert
          Assert.Equal(codeHandledByPolicy, result.StatusCode);
          Assert.True(retryCalled);
          }

          }

          public class StubDelegatingHandler : DelegatingHandler
          {
          private readonly HttpStatusCode stubHttpStatusCode;
          public StubDelegatingHandler(HttpStatusCode stubHttpStatusCode) => this.stubHttpStatusCode = stubHttpStatusCode;
          protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) => Task.FromResult(new HttpResponseMessage(stubHttpStatusCode));
          }


          If the declarations of policies are pulled out to methods (like SetWaitAndRetryPolicy1() in your posted code), an approach like above provides a more unit-test-focused way to test them.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jan 6 at 7:49

























          answered Jan 4 at 23:39









          mountain travellermountain traveller

          2,831819




          2,831819













          • This is a shortened version of a longer post (more information about the end-to-end integration approach particularly), at; github.com/App-vNext/Polly/issues/555

            – mountain traveller
            Jan 4 at 23:40



















          • This is a shortened version of a longer post (more information about the end-to-end integration approach particularly), at; github.com/App-vNext/Polly/issues/555

            – mountain traveller
            Jan 4 at 23:40

















          This is a shortened version of a longer post (more information about the end-to-end integration approach particularly), at; github.com/App-vNext/Polly/issues/555

          – mountain traveller
          Jan 4 at 23:40





          This is a shortened version of a longer post (more information about the end-to-end integration approach particularly), at; github.com/App-vNext/Polly/issues/555

          – mountain traveller
          Jan 4 at 23:40




















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54030145%2ftest-polly-retry-polly-configured-via-startup-configureservices-with-asp-net-c%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Mossoró

          Error while reading .h5 file using the rhdf5 package in R

          Pushsharp Apns notification error: 'InvalidToken'