Git Product home page Git Product logo

Comments (20)

stevejgordon avatar stevejgordon commented on June 21, 2024 5

This has been a common pain point I think. Historically (for better or worse) I've created an IHttpClientWrapper which wrapped the methods we needed, generally just SendAsync(HttpRequestMessage request).

Our implementation was then a singleton, holding onto a static HttpClient. The IHttpClientFactory looks to solve that part of the use case.

Our second reason for the wrapper was testing. We can mock up an IHttpClientFactory and setup the SendAsync method to return whatever HttpResponseMessage we want. This lets us quickly test how our code handles various response codes for example.

It would be nice if this library can provide a similarly simple way to return a response from a Mock of the interface.

Happy to share / chat more on our simple use cases if it helps?

from httpclientfactory.

martincostello avatar martincostello commented on June 21, 2024 1

If it’s useful, I’ve updated the samples for the test library I help maintain to use HttpClientFactory for integration tests: https://github.com/justeat/httpclient-interception/blob/master/samples/README.md

from httpclientfactory.

lambdakris avatar lambdakris commented on June 21, 2024 1

@martincostello checking out httpclient-interception and samples, looks good, thanks

from httpclientfactory.

rynowak avatar rynowak commented on June 21, 2024

Some interesting food for thought here: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-client

Spring's approach to this seems to be that you configure a 'mock server' and then point the client at it. I've read through most of their testing docs, and it seems focused so far on testing your app using the client, rather than mocking your external API calls.


We need to go deeper.

There are some existing libraries that do mocking directly at the HttpMessageHandler layer and seem pretty well-constructed.
https://github.com/richardszalay/mockhttp
https://github.com/justeat/httpclient-interception

I think ideally we'd just make sure that there's a recipe and sample for plugging these libraries in.

Here's an example of plugging in a different primary handler https://github.com/aspnet/HttpClientFactory/pull/30/files#diff-93b82f6c4aacbb74320ea2d4ca02de38R23

We could turn this into an extension method to make it obvious, that might be enough.

from httpclientfactory.

PureKrome avatar PureKrome commented on June 21, 2024

Yay for this!!! Would upvote this a bazillion times, if it was possible.

Hell, even I ended up making a library to help hijacking the response to what I wanted it to be for testing purposes: https://github.com/PureKrome/HttpClient.Helpers

from httpclientfactory.

glennc avatar glennc commented on June 21, 2024

The two strategies that HttpClientFactory enable are:

  1. Set the primary HttpClientHandler to your own type. This type can be constructed normally and doesn't really have any special logic that would make us need to have one in the box. We would show a one that doesn't make outgoing calls in our documentation. You could then copy this and use it to do whatever asserts you need in your tests. It could also be generated with a mocking library. Mocking HttpClientHandler only requires implementing SendAsync.

  2. Mock out the entire factory and return a mock HttpClient. This is far harder than the first option, but we would tell people that they could do this if they really needed to. We hope that most code doesn't depend on HttpClientFactory directly which limits the utility of this for most apps.

I am going to close this in favor of the linked docs issue. But I will continue looking in if you guys think there is some scenario that item 1 doesn't really cover then let me know.

from httpclientfactory.

stevejgordon avatar stevejgordon commented on June 21, 2024

@glennc I'm not clear on exactly what we'd expect to take a dependency on at this stage. I probably need to pull the code and have a play locally.

Say I have one named HttpClient registered and I want to use it from an ASP.NET controller for my action method to use to go get some external data. What would I take a dependency on there?

As I say, I'll try grabbing this locally and perhaps set up a simple scenario so I can see it in action.

from httpclientfactory.

glennc avatar glennc commented on June 21, 2024

I didn't make this clear either, but the intent here would be that you can:

  1. Use the HttpClientFactory. Seems like this makes sense to everyone
  2. Create a type that you accept in your controller that accepts an HttpClient and when registering you setup the type to get the named client you configured.
    2a. Within this you could create a dumb type that just has a HttpClient on it or you could actually put methods that make sense and delegate to the HttpClient in the type.

If doing 2 then you have something like MyAPIClient that you can accept in your controller and mock appropriately without ever needing to interact with HttpClient. Does that make sense?

I need to spend more time with it as well, I am re-hashing what we have talked about at the moment rather than talking about what I have used :).

from httpclientfactory.

stevejgordon avatar stevejgordon commented on June 21, 2024

@glennc Yes I think that makes sense. Your 2a sounds very similar to our current approach. I put together a quick and dirty example of how we generally use HttpClient currently and test dependant classes. This approach also solved the issue of reusing an existing HttpClient to save on many new connections.

https://github.com/stevejgordon/HttpClientExample

from httpclientfactory.

stevejgordon avatar stevejgordon commented on June 21, 2024

Thinking out loud to explain how I originally imagined this library might work (for our basic cases)..

An interface (IHttpClient) which defines the various methods on HttpClient (understand this is a fairly fundamental change). In our classes we depend on IHttpClientFactory (or some accessor class) asking for a named IHttpClient. We can then mock the IHttpClientFactory (or IWhatever) and set it up to return a mocked IHttpClient. We can then control the return values of the IHttpClient for our testing needs.

I understand this very likely has a lot of issues and things I've not considered (and possibly falls outside the scope of the intentions here) but I wanted to share this since it might help to explain my thinking.

Your 2a example and our current approach is close but it feels like there's more plumbing we need to do than I would like. We'd like an easy way to depend on a framework interface which gives us the named (I)HttpClient that we need without having to create our own wrapper / dumb type.

from httpclientfactory.

PureKrome avatar PureKrome commented on June 21, 2024

@stevejgordon convo is starting to sound like this epic issue from a few years back....

from httpclientfactory.

stevejgordon avatar stevejgordon commented on June 21, 2024

Thanks for the link @PureKrome. I've scanned down that quite long thread and would need more time to review everything that's been said.

One point (which may be more relevant in corefx) is that one of the concerns of adding an interface for HttpClient is that if a new member is added it breaks existing classes implementing the interface. Perhaps that problem goes away in C#8 with default interface methods? That sounds like the problem that feature is intending to solve. I can't really see why the Interface would change that often though.

In my case I'm also starting to think about more intelligent design that might simplify the number of places we need to take dependencies on HttpClient and therefore mock and test it.

from httpclientfactory.

lambdakris avatar lambdakris commented on June 21, 2024

So was there a resolution on this? Here it looks like it is still todo: https://github.com/aspnet/HttpClientFactory/wiki/Consumption-Patterns#valuesservice-test

from httpclientfactory.

rynowak avatar rynowak commented on June 21, 2024

@glennc - do you want to follow up on the wiki article?

@lambdakris - we decided to not implement anything specific to the factory because we felt like existing options for testing with HttpClient work pretty well. Is there something specific you want to discuss?

from httpclientfactory.

lambdakris avatar lambdakris commented on June 21, 2024

I was just curious what the pattern/recipe for setting up tests was now. Previously I would create a fake HttpMessageHandler and add it to the HttpClient instance. I suppose now the pattern is supposed to be to add the fake HttpMessageHandler to the HttpClientFactory?

from httpclientfactory.

martincostello avatar martincostello commented on June 21, 2024

That's what I've been doing, yes. If you want to test any custom handlers you might also have, then you just need to make sure it's the root handler in the chain.

from httpclientfactory.

rynowak avatar rynowak commented on June 21, 2024

I'm going to open this back up to track us updating the docs and wiki. Thanks for the feedback.

from httpclientfactory.

glennc avatar glennc commented on June 21, 2024

@scottaddie, you are working on docs for testing right?

from httpclientfactory.

scottaddie avatar scottaddie commented on June 21, 2024

@glennc Issue dotnet/AspNetCore.Docs#7847 is tracking the docs work.

from httpclientfactory.

rynowak avatar rynowak commented on June 21, 2024

Closing this since it's tracked on the docs repo.

from httpclientfactory.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.