Comments (20)
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.
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.
@martincostello checking out httpclient-interception and samples, looks good, thanks
from httpclientfactory.
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.
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.
The two strategies that HttpClientFactory
enable are:
-
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. MockingHttpClientHandler
only requires implementingSendAsync
. -
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.
@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.
I didn't make this clear either, but the intent here would be that you can:
- Use the HttpClientFactory. Seems like this makes sense to everyone
- 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.
@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.
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.
@stevejgordon convo is starting to sound like this epic issue from a few years back....
from httpclientfactory.
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.
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.
@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.
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.
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.
I'm going to open this back up to track us updating the docs and wiki. Thanks for the feedback.
from httpclientfactory.
@scottaddie, you are working on docs for testing right?
from httpclientfactory.
@glennc Issue dotnet/AspNetCore.Docs#7847 is tracking the docs work.
from httpclientfactory.
Closing this since it's tracked on the docs repo.
from httpclientfactory.
Related Issues (20)
- How Can I Use ClientCertificates in HttpClientFactory.CreateClient HOT 4
- Getting a endless HttpMessageHandler cleanup cycle HOT 29
- Adding a HttpMessageHandlerType that is registred as Transint in IServiceCollection creates strange results HOT 14
- Microsoft.Extensions.Http.Polly.dll is code signed but Polly.Extensions.Http.dll and Polly.dll are not HOT 4
- Don't capture the ExecutionContext in Timers created for expiry HOT 1
- Asp.net restart: Cannot find method HOT 7
- Error: Unable to resolve service for type 'Microsoft.Extensions.Logging.ILogger' while attempting to activate HOT 4
- Test failure: Factory_CleanupCycle_DisposesEligibleHandler HOT 6
- System.InvalidOperationException: Collection was modified; enumeration operation may not execute. HOT 7
- An error occurred while writing to logger(s) HOT 3
- HttpClientFactory Causes High CPU? HOT 33
- Test failure: SuppressScope_False_CreatesNewScope HOT 3
- Running Tests Locally Not Working HOT 4
- In the controller, how do I find the specified type client by name HOT 2
- NullReferenceException in ActiveHandlerTrackingEntry with 2.2.0 preview 3 HOT 8
- Confusing DI behaviour HOT 2
- Remove MessageHandler - Logging Message Handler HOT 5
- Cleanup timer captures logging scopes HOT 3
- Question - HttpMessageHandler access session HOT 2
- Is it possible for HttpClientFactory to target .NET Standard? HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from httpclientfactory.