You are mocking the HttpClient the wrong way

Sdílet
Vložit
  • čas přidán 19. 06. 2024
  • Get started with Octopus Deploy: oc.to/nickchapsas
    Check out my courses: dometrain.com
    Become a Patreon and get source code access: / nickchapsas
    Hello everybody I'm Nick and in this video I will show you what is my prefered way to mock the HttpClient in .NET. Many people are using Moq's Protected feature to use reflection and access the SendAsync method by name but I really don't like this approach. Let's see what I do instead.
    Give MockHttp a star on GitHub: github.com/richardszalay/mock...
    Don't forget to comment, like and subscribe :)
    Social Media:
    Follow me on GitHub: bit.ly/ChapsasGitHub
    Follow me on Twitter: bit.ly/ChapsasTwitter
    Connect on LinkedIn: bit.ly/ChapsasLinkedIn
    This video is sponsored by Octopus Deploy
    Keep coding merch: keepcoding.shop
    #csharp #dotnet #testing

Komentáře • 166

  • @nickchapsas
    @nickchapsas  Před rokem +32

    I forgot to mention in the video that this doesn't apply to you if you are using a third party library like Refit, RestSharp, Flurl etc. Those provide testable interfaces by default and you go over the HttpClient entirely.

    • @v.n.7578
      @v.n.7578 Před rokem

      Hi Nick, love your content. Could you explain the Moq .Setup() and how it works behind the scenes?

    • @nickchapsas
      @nickchapsas  Před rokem +4

      @@v.n.7578 I have made a video making my own mocking library that explains that here: czcams.com/video/9kEURoqHKZ0/video.html

    • @danutz_plusplus
      @danutz_plusplus Před rokem +4

      But why not go a step further and just write your own abstraction in the business library, ex an IUserValidator with a method IsValidUser, and isolate your business code from the networking stack fully. This will simplify the mocking that you need to do (you no longer need to setup the httpclient at all for the mock). And then have a gateway library/class which implements that IsValidUser abstraction and which actually configures the httpclient as it would be in production.
      This way you can have your unit tests isolated from the out-of-process calls without bothering with the complexity that comes with the httpclient. And then you can write integration tests for the gateway library to actually test the httpclient integration with github, as it would be in production.
      Also, If you attempt to mock the httpclient, that sounds very close to mocking the communication interface that github offers at that point. So if they change it at some point, you'll either remain with a mismatch with the way you're mocking it vs how it is used, or you'll need to adapt both the mocking code and also the logic that setups the httpclient.
      Anyway, just a thought. I hope I'm not missing context.

    • @NickSteffen
      @NickSteffen Před rokem

      @@danutz_plusplus I think it was just a simplistic example. The info given by the video still applies whether you are testing this class or a gateway class.

    • @pilotboba
      @pilotboba Před rokem

      @@danutz_plusplus Then how do you test the IUserValidator implementation? It's turtles all the way down.

  • @RichardSzalay
    @RichardSzalay Před rokem +13

    Thanks for the shout out, Nick! I'm happy that the library's been useful.

  • @alexanderkvenvolden4067
    @alexanderkvenvolden4067 Před rokem +91

    I think you shouldn't mock HttpClient. It's doing the best it can!

    • @paulrockerdale9409
      @paulrockerdale9409 Před rokem

      I like to have many in memory integration test where all infrastructure calls are mocked out and are fast and not flakey... Then smoke test with real http calls after a build

    • @uumlau
      @uumlau Před rokem

      You beat me to it - by two months. ;)

  • @RahulSingh-il1xk
    @RahulSingh-il1xk Před rokem +17

    In our project, we use Moq.Contrib.HttpClient package to mock the clients. It's fairly simple too. Great video btw.

  • @shadowsir
    @shadowsir Před rokem +4

    I never got why people insist on testing library code. I usually just pass a Func to the function. In the actual code, I'd pass in a function that uses the HttpClient. In tests, I'd pass in something that takes a T and returns a Task of HttpResponse. No need for mocks at all...

  • @nickchapsas
    @nickchapsas  Před rokem

    Get started with Octopus Deploy: oc.to/nickchapsas

  • @stefanbogdanovic590
    @stefanbogdanovic590 Před rokem +3

    Exactly what I needed! I needed this yesterday! Thank you Nick you are magician!

  • @aughey
    @aughey Před rokem +15

    I've always created my own IHttpClient sort of interface that implements simple async Get, Put, and Post methods, sometimes with a similar Factory class to get the client by name. This way I can easily Mock those simplified versions, and adapt to the system HttpClient for production.

    • @willi95
      @willi95 Před rokem

      I used to do the same thing, it started nice and simple, then implemented setting custom headers and getting headers back, things like that.
      Then ms implemented async await and I added support for this too. Then the next person asked for URL encoded content type, then multipart content for file upload and so on...
      Next problem was: for our internal services we started creating client nuget packages => always an additional package to carry with the client.
      We than switched to that were generating the usable clients from the openapi spec and then we used them for integration testing of the controllers of the same "micro" service, which seems for me like the most optimal approach for internal services.
      For external services I now just create interfaces/clients like the ones you get generated and mock these interfaces for unit tests. I dropped really unit testing the external client implementations itself, just had a disabled integration test that was executed manually against the real service, but the lib Nick showed seems very promising, seems like it's worth trying out.

  • @judas1337
    @judas1337 Před rokem +2

    This video is great. I just started using this way half a year ago. Just watching this 14 min video would have saved me half a day to a days work. So from now on I can just link this video to coworkers.

  • @kaiserbergin
    @kaiserbergin Před rokem +1

    Thanks for the vid. I've been using Wiremock for integration testing, but it always felt a bit heavy for unit tests. This looks like a great tool to use... And we recently got started using Refit, which has been really helpful in simplifying and standardizing our http clients. Great content, as usual!

  • @strawhenge5007
    @strawhenge5007 Před rokem +4

    This is actually my go to example of the Open Closed Principle. By passing in your own message handler class, you can extend the behavior of HttpClient without changing the HttpClient code.

  • @myemailvl
    @myemailvl Před rokem +2

    Cool. Another way to do it. Make kind of "adapter" or "wrapper" that implements interface with all methods you need, like SendAsync. And this "adapter" use actual HttpClient to do stuff. But when you need to mock it you mock the interface. Minor downside if you use IHttpClintFactory you need to "adapt" this type too. In the way that IHttpClientFactoryAdapter returns HttpClientAdapter wrapped around HttpClient that provides by IHttpClintFactory injected into IHttpClientFactoryAdapter.

  • @nsedwards
    @nsedwards Před rokem

    Dude, great video as always, just 1 small point, and it's probably just my own OCD kicking in, the use of Mock for variable naming should be at the start of the name i.e. _mockHandler and not _handlerMock :D

  • @Misterjuzz
    @Misterjuzz Před rokem

    In order to test a couple of Controllers in our web application (without front-end), i have a separate xUnit test project which always has to login to the application before testing any action. I store the token in a static file so that if i'm running multiple tests I need only login once. Thing is, every Test class class their respective service in the Act. The service has re-usable methods as currently the scope of the Controllers is to simply Get and Put - and these are the only 2 methods in each Service. This way i simply cut down on repeated code - as I have many test cases, each one testing with different sets of data.
    In order to send data, I use RestSharp. The project is very simple, and while Postman could already do all this, these 2 Controllers require lists of data to be sent - which runnes of Postman cannot do properly.

  • @pablocom
    @pablocom Před rokem

    This helped me a lot! Thank you so much for sharing 😍

  • @vitaliykoritko5080
    @vitaliykoritko5080 Před rokem

    Nick, thank you for video, I'm using WireMock. Btw Regarding Moq usage for primitives like string, int, bool etc. you can pass just value instead of It.Is

  • @SandGrainOne
    @SandGrainOne Před rokem

    We've created a DelegatingHandler for use in unit tests. Through that we can obtain the request object and provide a response.

  • @Pookzob
    @Pookzob Před rokem +1

    At work we abstract the HttpClient behind an Interface: IWebRequestFactory.
    Service handles urls and application flow, the implementation of IWebRequestFactory (f.eg jsonWebRequestFactory) handles the actual call to the external API.
    I believe that the service belongs to the domain and web requests to other apis are an implementation detail not belonging to the domain. YMMV.
    Thanks for plugging the mocking libs though! Will definitely look into those.

    • @nickchapsas
      @nickchapsas  Před rokem +1

      Oh interesting. How are you dealing with the IHttpClientFactory then? is that something your IWebRequestFactory implementations use?

    • @Pookzob
      @Pookzob Před rokem

      @@nickchapsas TBH we don't even use that interface, it was news to me so thanks for that!
      We have a separate, homegrown, Common.Web lib that handles HTTP requests and parsing to a given type. We use it primarily for internal apis where we use bearer auth and objects represented as Json as response.
      We use HttpClient directly in the lib. IIRC we reuse the client by having it as a static field (might be bad practice but keeps the lib self-contained with no setup required, and I believe MSFT recommended it at the time we built it in NET standard 2.0).

    • @markfay9649
      @markfay9649 Před rokem +1

      @@nickchapsas I do something similar by creating an IHttpClientFactoryWrapper and an IHttpClientWrapper, with concrete class that accept an HttpClient in the constructor, then I only expose the HttpClient methods my code uses. this allows for full encapsulation of the HttpClient with little to no understanding of how the HttpClient actually sends requests

    • @Pookzob
      @Pookzob Před rokem +1

      @@markfay9649 so you're basically making a facade for testing purposes? Also a smart idea, even if it's a somewhat leaky abstraction 👍

  • @Myuuiii
    @Myuuiii Před rokem

    Loving the content! Keep it up!

  • @josda1000
    @josda1000 Před rokem +2

    MockHttp is excellent, been using it for about three years now.

  • @evancombs5159
    @evancombs5159 Před rokem +1

    I needed this last week when I was needed to mock an HttpClient. Would have saved me time on research.

  • @narebinhaa
    @narebinhaa Před 7 měsíci

    @nickchapsas is like batman. He's always three steps ahead.

  • @nickst0ne
    @nickst0ne Před rokem

    My current project has a very high code coverage requirement and I didn't know of such projects as httpMock. So I just created a facade with an interface. Since I only have the SendAsync method to verify, with basic messages, I was able to implement this quickly.

  • @maikschonfeld5216
    @maikschonfeld5216 Před rokem

    Very cool topic. Had to solve that very problem not even a week ago and found MockHttp as solution (and of course gave it a star).
    Thank you for this helpful video.
    also: this: prop = default!; looks interesting. what exactly does it do?

    • @nickchapsas
      @nickchapsas  Před rokem

      It tells the compiler that the property isn't nullable and to stop showing that nullability warning because I pinky promise to initialize it

    • @maikschonfeld5216
      @maikschonfeld5216 Před rokem

      @@nickchapsas ah, cool. The only way I use so far is: prop = string.Empty but that looks cool for properties one knows will not end up being null. Thanks for responding.

  • @user-xd7xm6gd2p
    @user-xd7xm6gd2p Před rokem

    What great timing, I was just trying to mock an HttpClient over the weekend. I started out using the Moq hack but trying to debug expected parameters was a pain, so I ended up rolling my own HttpMessageHandler. MockHttp looks pretty useful, I'll check it out if my custom handler starts getting too complicated

  • @7th_CAV_Trooper
    @7th_CAV_Trooper Před rokem +4

    Mocking the HttpClient: "Hey you stupid HttpClient, you think you're really something don't you. Well you're not."

  • @brianm1864
    @brianm1864 Před rokem +3

    We use Flurl... the HttpTest class makes it so easy to mock and validate the calls being made in the tests.

    • @nickchapsas
      @nickchapsas  Před rokem +1

      I personally prefer Refit over Flurl. I think it has a better interface approach and library design

    • @brianm1864
      @brianm1864 Před rokem +1

      @@nickchapsas Never heard of it, but I'll definitely have to check it out!

    • @anthony8090
      @anthony8090 Před rokem

      @@nickchapsas What's wrong with Flurl specifically? I find it to be wonderful.

    • @nickchapsas
      @nickchapsas  Před rokem +1

      @@anthony8090 There is nothing really wrong with it, I just prefer the approach that Refit takes way more than the Flurl one and since you can only chose one of them I can't use Flurl

    • @anthony8090
      @anthony8090 Před rokem

      @@nickchapsas fair enough

  • @gavinlangley8411
    @gavinlangley8411 Před rokem +7

    I think the problem here is that the HttpClient is a tool and you really want to be mocking calls at the logical Http interface level instead. You can make it super easy by adding typed HttpClients with interfaces. The HttpClient is the 'implementation' you are trying to mock (maybe with an in memory item or a file or a databse call) HttpClient is not really the interface you should be mocking.

    • @user-qf2xk1fg6e
      @user-qf2xk1fg6e Před rokem +1

      I thought exactly the same thing. What is the point to check how HttpClient works? I think it's better to check your app logic that uses HttpClient. That's why I would write a wrapper around the client, that would be mockable. But anyway, this video was useful, I did not think about this problem. Now I know about it.

    • @tplummer217
      @tplummer217 Před rokem

      This is how i do it.

  • @paulrockerdale9409
    @paulrockerdale9409 Před rokem

    Not for this library to resolve...but something I've been mulling over... I've not worked much with grpc... But if I switched out http calls to use grpc could my tests be ignorant of what protocol is used to send and receive data? Library that could do that might be awesome

  • @paulrockerdale9409
    @paulrockerdale9409 Před rokem

    One issue I had with testing chatty APIs is when a method or behaviour has multi calls with the same httpclient... I think I ended up putting in logic in my custom fake (not mock) handler class. I love wiremock as it allows me match on the request... But this mock library looks totally intriguing. I think there is room for both libraries

  • @bhavikrupa9092
    @bhavikrupa9092 Před 11 měsíci

    How does one mock the http request while unit testing using Postman or parasoft

  • @jeroentje260
    @jeroentje260 Před rokem

    We use a package called Codenizer.HttpClient.Testable, Which allows you to easily setup the requests & responses for the http handler. This allows you to easily setup all this. Which looks very simular to the MockHttp

  • @frankbanini8884
    @frankbanini8884 Před rokem

    Great video. I like the brevity of the code. How can i get the code in the video?

  • @carljohnlopez5425
    @carljohnlopez5425 Před rokem

    Is it proper way to for instance save the httpclient in a static property that was set onstart of the webapp?

    • @nickchapsas
      @nickchapsas  Před rokem

      No you want to be using the HttpCliemtHandler and let that create them for you every time you need to use them

  • @futurexjam2
    @futurexjam2 Před rokem

    if you need Task, you can just use await Task.Run(() => return new HttpResponseMessage() { StatusCode = System.Net.HttpStatusCode.OK };); and do not bother with HttpClient and reflections. Also you can write custom MockHandler which can override SendAsync function.

  • @DoronGrinzaig
    @DoronGrinzaig Před rokem +1

    Thanks for the vide Nick! but...
    It looked amazing in the video, but in practice, it has some very significant short comings.
    Most importantly, most HTTP POST APIs are taking their parameters as json body, the library doesn't have a matcher for json.
    Basically you need to serialize the DTO and use that as the body string for matching, needless to say, matching by string is awful, spaces, or change of the order of the properties would break you unit tests.
    Also not being able to Respond with chaining like you can for matching is very annoying and not intuitive.
    Obviously I cannot complain about an open source that someone kindly enough donated his time for it, but the library is far of being perfect.
    Microsoft really need to step up here and allow a proper way of mocking HttpClient, it would have been so much simpler had there was simply an IHttpClient.

  • @antonmartyniuk
    @antonmartyniuk Před rokem +2

    I really like the library. I prefer using Refit hidden by interface, so it's a breathe to write tests without toching HttpClient. But this library can become handy. Also I prefer Mock library over NSubstitute, because Mock is way more powerful. While NSubstitute has a bit more nice syntax but you can shoot youself in the foot because you can call extensions methods for mocking from any interface. While in Mock you can't do it. And also Mock has way more options for verifying calls of methods. Etc...

    • @nickchapsas
      @nickchapsas  Před rokem

      Can you elaborate on what Moq can do that NSubstitute can't?

    • @rpm4598
      @rpm4598 Před rokem

      @@nickchapsas Did you mean... "that NSubstitute can't?"

    • @nickchapsas
      @nickchapsas  Před rokem

      @@rpm4598 Yeah sorry fat fingers. Fixed it thanks!

    • @sodreigor
      @sodreigor Před rokem

      Not sure if I just did not find the correct way to do it, but once I needed to mock a couple methods of the ILogger interface, and the only way I succeeded was with Moq.

    • @antonmartyniuk
      @antonmartyniuk Před rokem +1

      @@nickchapsas yes, sure. 1. Moq force you to declare the type as Mock and I find it as an advantage. Moq uses a more representative notation. Anyone, just reading the code can know that we are creating a mock object. That way you can only setup arrange things only on Mockable types while using NSubstitute (NS) you can use its extension methods even on real classes (interfaces) and fail. When you write Received() assert with NS you can mismatch the methods order and the test will crash: _service.Received(1).SetAsync(...) you can write Received before and after SetAsync. When using Moq you can't fail this. 2. Received method in NS just accepts a single number, while Moq has a big variety of options. 3. Moq provides more matching arguments. 4. With Moq it is much easier to get the arguments values in the Return statement. 5. I prefer Moq's syntax of Callback over NS's When-Do. 6. With Moq it is more clear when you specify when a method throws an exception. I personally used NS in the past and when I tried Moq and showed it to my team - we now use Moq and like it more

  • @dukefleed9525
    @dukefleed9525 Před 4 měsíci

    it's pretty hard to correcly mock even the client side behavior of cookies with this library, if the mocked response provides a set-cookie header, the subsequent invocation done via the httpclient doesn't contains the cookie. how to fix this ?

  • @jametime7491
    @jametime7491 Před rokem +1

    Can you please make a video on efcore unit tests(checking the method) and integration test(tests to check for queries). I am really confused because this would require two separate projects also to share bogus data with all the tests initally pushed to the db

    • @nickchapsas
      @nickchapsas  Před rokem +3

      A video for EF Core unit testing is coming I think next Thursday if my scheduling is correct

    • @neppe4047
      @neppe4047 Před rokem

      @@nickchapsas I can't find such video in the channel. Is it cancelled or pushed back in the backlog?

  • @kwibuske
    @kwibuske Před rokem

    I'd prefer to wrap all my HTTP calls into a "Facade" service. This Facade service will have an interface which prevents the need to mock out the HTTP calls and is easily mockable.
    Example:
    Public class GithubApiService : IGithubApiService {
    public async Task GetUserAsync() {
    // code with HttpClient comes here
    }
    }

    • @nickchapsas
      @nickchapsas  Před rokem

      What we are testing is the facade service

  • @yoanashih761
    @yoanashih761 Před rokem

    What is ILoggerAdapter?

  • @pilotboba
    @pilotboba Před rokem

    Noice!
    How would you mock the client when you have an API that throttles and you want to test your retry logic works when you get a TooManyRequests (429) response?

    • @nickchapsas
      @nickchapsas  Před rokem +1

      You can set up the response to return 429 and then use the Verify method of Moq (or Recieved if you're using NSubstitute) to validate how many times your method was retried via the times it was called

    • @RichardSzalay
      @RichardSzalay Před rokem +1

      You can setup ordered mocks (using mockHttp.Expect) so that the first call returns 429 and then second succeeds. There's a similar example in the README that revolves around an oauth refresh cycle.

  • @ArgeKumadan
    @ArgeKumadan Před rokem

    My question is, since the Handler is an abstract class, why don't u just create your own type derived from that and make it testable? I don't even know if that's a proper question. I am a bit confused (:

    • @nickchapsas
      @nickchapsas  Před rokem +2

      You can but you don't have to. Why would you write a full type that you have to manage and change for every test when you can use something that does it for you

    • @ArgeKumadan
      @ArgeKumadan Před rokem

      @@nickchapsas Thanks for the answer, I was just just thinking how it would be possible. Of course there is always a better way instead of custom implementations :))

  • @codingbloke
    @codingbloke Před rokem +1

    Thanks Nick. Excellent content. Currently I am using the hacky .Protected() but I'm going to stop doing that and use this HttpMock instead on back of this video. I suspect that using features like .When() will improve the appearance of my code especially in parameterized xUnit Theory tests.

  • @Iingvarka
    @Iingvarka Před rokem

    You can create TestHttpMessageHandler from abstract class HttpMessageHandler which accept interface what you gonna mock
    + you can create extension for mocking calls like GetGithubUser which will contain arguments matching and response. It will be more readable and easy to use imho
    Also you can use typed HttpClient instead of factory and get rid of extra mock

    • @nickchapsas
      @nickchapsas  Před rokem

      Obviously but why waste your time building something you have to configure every time for every test and every client. It's a very clucky solution

    • @Iingvarka
      @Iingvarka Před rokem +1

      @@nickchapsas I wouldn't say it is a very cluncky solution tho. It is one more way to avoid using Moq's Protected feature. At the end you gonna get something like what MockHttp provided but instead of learning MockHttp configuration you can use familiar Moq configuration.

    • @nickchapsas
      @nickchapsas  Před rokem

      @@Iingvarka When you have 3 clients with 1-10 endpoints each and you want to mock each endpoint in multiple ways then yes it is very clunky

    • @Iingvarka
      @Iingvarka Před rokem

      ​@@nickchapsasYou still need to mock 1-10 endpoints for each clients for MockHttp. It seems there is some miscommunication. If you take a look at MockHttpMessageHandler implementation it gets BackendDefinitionBehavior in constructor so instead of passing BackendDefinitionBehavior you pass your mock which can be configured using Moq.

    • @shahzad.hassan
      @shahzad.hassan Před rokem

      @@nickchapsas The solution that Igor suggested seems identical to what I suggested with the code, I think, and CZcams didn't delete it this time. Please check
      Not sure how it is going to be a clunky solution. You would still have to use .When, .Expect or .Respond methods of MockHttp to setup the expectation on the MockHttpMessageHandler. Same way, if you create a TestMessageHandler which accepts an interface, you setup the expectations on that interface for each test, but you could use the familiar Moq library, instead of learning new one.
      Don't get me wrong though, I think MockHttp is great, and it has some cool fluent methods to setup however you want it. However, for simple cases I wouldn't bring in the whole library but would go with the Decorator pattern solution.

  • @joro550
    @joro550 Před rokem +2

    Meh. I just create my own implementation of httphandler and pass things through the constructor. Have to admit the whole "mock everything" form of testing isnt really my style, especially when the book everyone says is the go to book on tdd (the kent beck book) says to test behaviour and not implementation.

    • @FleetingDream755
      @FleetingDream755 Před rokem

      Yeah, same here. I do mock the httpclient by wrapping it in an interface that exposes the functions I need. The behavior I'm testing is NOT what the httpclient is doing but rather the exception throwing or whatever else I'm interested in.

  • @marvinbrouwer459
    @marvinbrouwer459 Před rokem

    Hi,
    I'm just wondering why in your example you mock the HttpMessageHandler, while the HttpMessageInvoker just has a:
    public virtual HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)
    It doesn't invalidate the rest of the video, I was just wondering why you wouldn't use that instead?

    • @nickchapsas
      @nickchapsas  Před rokem

      Because it’s synchronous and it’s not used

  • @zaoralj
    @zaoralj Před rokem

    What about to wrap http calls to you own service with service which you can can mock without any issue ?

    • @nickchapsas
      @nickchapsas  Před rokem

      Sure but if you do that you might as well use a client like Refit, Flurl or RestSharp that makes it even easier.

  • @benrussill2667
    @benrussill2667 Před rokem +2

    I'm sorry, and I know this isn't related to the current video, but you previously did a video saying AOP wasn't useful since you couldn't do DI/IOC (properly), which I fully agree with you.
    In your video of c#11 changes to attributes, you show how to create attributes with generics + DI/IOC. Does this at all change your opinion of AOP (essentially just meta -programming)?

  • @bramburn
    @bramburn Před rokem

    I’m lost. How is this different to using web application factory?

    • @nickchapsas
      @nickchapsas  Před rokem +1

      WebApplicationFactory is for integration testing. This is for unit testing

    • @bramburn
      @bramburn Před rokem

      @@nickchapsas ahh ok yeah might need it to add it on the title.

  • @Steven_Olson
    @Steven_Olson Před rokem

    I usually just do so under my breath, I wouldn't want it to get offended 😂!
    Seriously however thanks for the vid 🙂.

  • @shahzad.hassan
    @shahzad.hassan Před rokem

    Hi Nick, I added my comments last night but they are not appearing here, any idea why?

    • @nickchapsas
      @nickchapsas  Před rokem

      CZcams false flags some comments and deletes them automatically usually if they have links or code. I never delete comments.

    • @shahzad.hassan
      @shahzad.hassan Před rokem

      @@nickchapsas I see, thanks. It had a link to a gist. How can I share that?

  • @snapching
    @snapching Před 9 měsíci

    Please use the typed client and an interface that reflects the business request for data, and the business data result. No business wants to know about httpclient, and hence does not need to test or mock that implementation

  • @tplummer217
    @tplummer217 Před rokem

    You can also wrap the httpclient up with a dedicated class which implements an interface. Mock that.

  • @teodorchirileanu
    @teodorchirileanu Před rokem

    wow nice tan!

  • @fernandoluiz4593
    @fernandoluiz4593 Před rokem

    What is the problem of creating a internal class inherited from HttpMessageHandler for test purposes? You could place any logic inside the overriden SendAsync().

    • @fernandoluiz4593
      @fernandoluiz4593 Před rokem

      I thought for 2 minutes and realized I would have to create a file for each test class in order to keep it clean.

  • @2SHARP4UIQ150
    @2SHARP4UIQ150 Před rokem

    Am I missing something.? Mocking is mainly used for unit testing. "Mocking HttpClient" is a concept hard for me to wrap up in my head. You mock an HttpClient dependency; handlers. Otherwise, I will consider integration testing. By the way, great content; I love your content.

    • @nickchapsas
      @nickchapsas  Před rokem +2

      You mock the HttpClient call so you don't actually call the service over the wire. This is part of unit testing. In integration testing you would call the service or a service responsing in the same manner of the real service

    • @2SHARP4UIQ150
      @2SHARP4UIQ150 Před rokem

      ​@@nickchapsas Probably, I shouldn't have mentioned the integration test to my point. I mock Httpclient Handlers, as my understanding handlers are httpclient dependencies. However, I can't entirely agree with the term mocking httpclient. There are httpclient methods and dependencies that can't be mocked. But, do not get me wrong, I think your strategy is flawless.

  • @alirezanet
    @alirezanet Před rokem

    Cool library, but it is also clean if we create our own MockHttpMessageHandler that doesn't do anything ...

  • @ytxzw
    @ytxzw Před rokem

    Nick, why do you use private variables names starting with _ isn't this annoying?

    • @nickchapsas
      @nickchapsas  Před rokem

      Nop. It’s very descriptive. I can distinguish class fields and variables in a method without having to check which is what

    • @ytxzw
      @ytxzw Před rokem

      ​@@nickchapsas I usually follow MS code guidelines but now I see that MS changed the rules recently or maybe not so recently? "_ will show all of the object-scoped members." I'm not convinced to this one, because it is just faster to type letters not to search _ sign on keyboard if you want to refer the variable. Idk. It confused me right now a lot. I usually try to write the code in the simplest way possible, but I never thought about distinguishing object variables via name prefix. I tend to declare and initialize the variables as late as possible and keep them very shortly. I'm also confused when somebody passes object to methods as arguments and modifies them in place [we have the ref keyword for that right? but nobody uses it]. Maybe the IDE should color the names according to scope?

    • @nickchapsas
      @nickchapsas  Před rokem

      @@ytxzw It's been like this for a long time, at elast 6 years. You can't assume that everyone will use the same IDE or the same color scheme.

    • @ytxzw
      @ytxzw Před rokem

      @@nickchapsas of course not, the same i can't assume that everybody will prefix the object variable names. In my opinion it is insane situation if somebody wrote the huge class and can't distinguish the purpose of the variables in its methods - so the issue is elsewhere actually. If you have nice slim methods than it is no problem to see what I what. People tend to overcomplicate simple things. Maybe it is just me, but I see it totally wrong to use the lowdash prefix. If it is really needed than the internal class would solve the issue better in my opinion (assuming those are all private parts that still can be publicly exposed anyway).

    • @nickchapsas
      @nickchapsas  Před rokem +1

      @@ytxzw That's completely subjective. You might find it insane but I, and all the devs I ever worked with, find it completely logical. Also, you can enforce coding standards which source analyzers which is a framework level thing so it works everywhere.

  • @graycleary
    @graycleary Před rokem

    With this being an open source library it restricts usage within companies who value high security. Microsoft should buy this or implement it themselves.

  • @vmachacek
    @vmachacek Před rokem

    still too complicated. What is wrong with hand written mocks, for each test or test class?

    • @nickchapsas
      @nickchapsas  Před rokem +1

      Hard to manage especially when you have 5 clients and 2-4 behaviours each

  • @T___Brown
    @T___Brown Před rokem

    Why inject the factory? You can inject the client by registering with the object type.

    • @nickchapsas
      @nickchapsas  Před rokem

      You should not inject the client. You should inject the factory and let it create the client per request. That’s how the factory and the client are supposed to work

    • @T___Brown
      @T___Brown Před rokem +1

      @@nickchapsas why? I dont believe so.

    • @T___Brown
      @T___Brown Před rokem

      Look at services.AddHttpClient(); it lets you define your httpclient for injection via httpclientfactory and your configuration is done at startup vs hard coded and multiple times. It does name resolution to determine which class gets which httpclient

    • @PovilasPanavas
      @PovilasPanavas Před rokem +1

      We at work started with best intentions and `IHttpClientFactory`. But we ended up using `services.AddHttpClient();`, exactly like you're saying. So far, didn't had any issues. Also, I do believe that internally still HttpClientFactory is used when we register AddHttpClient.
      Leaving a comment in case someone will give some actual arguments why IHttpClientFactory would be useful.

  • @bilbobaggins8953
    @bilbobaggins8953 Před rokem

    I can't do anything right and I will never get it

  • @Anequit
    @Anequit Před rokem

    Shouldn't you only be using 1 HttpClient and reusing it throughout the project?

    • @nickchapsas
      @nickchapsas  Před rokem

      Nop. It's the handlers you should be reusing not the HttpClient, that's why IHttpClientFactory is recommended. Because it reuses the handlers behind the scenes but it creates new HttpClients which prevents you from having DNS issues

    • @Anequit
      @Anequit Před rokem

      @@nickchapsas Interesting, I've always just used and reused the same HttpClient throughout the whole application.

    • @nickchapsas
      @nickchapsas  Před rokem +2

      @@Anequit That's a bad practice. DNS changes can put your app in an unrecoverable state unless you restart it

    • @Anequit
      @Anequit Před rokem

      @@nickchapsas Good to know I'll work on learning that HttpClientFactory then

  • @TangoMikeOscar
    @TangoMikeOscar Před rokem

    I'm surprised you don't mention here that the HttpClientFactory should really be returning an interface not a concrete class then you can mock it a while lot easier. Since a lot of the core framework is supposed to be very extensible and pluggable this seems like a massive omission.

    • @nickchapsas
      @nickchapsas  Před rokem +1

      The IHttpClientFactory is a .NET class cna it returns a concrete HttpClient. We can't change that.

    • @RaMz00z
      @RaMz00z Před rokem

      Actually it is isn't an omission at all, it's completly by design.
      You shouldn't mock HttpClient, that's the reason...
      Mock the methods using HttpClient, not HttpClient itself. You are not covering anything if you do that.
      Microsoft doesn't expose an interface because they don't want you to do that. Simple.

  • @Nikkes02
    @Nikkes02 Před rokem

    What if I need to mock a mockingbird?

  • @bruno.arruda
    @bruno.arruda Před rokem

    This project hasn't been update for 3 years.

    • @nickchapsas
      @nickchapsas  Před rokem +3

      HTTP hasn't changed in 10 years

    • @bruno.arruda
      @bruno.arruda Před rokem

      @@nickchapsas fair.

    • @RichardSzalay
      @RichardSzalay Před rokem +2

      Honestly there hasn't been a need to add any major features - the last major version was only because someone at Microsoft asked for it to be strongly named. Needless to say, if HttpClient changes in the future I'll post an update. Beyond that, I might add some System.Text.Json-specific syntax sugar if I ever decide to drop support for older frameworks.
      I still use it all the time, if that helps.

  • @DJTimeLock
    @DJTimeLock Před rokem

    Bold of you to assume i mock anything

  • @Lazzerman42
    @Lazzerman42 Před rokem

    I try not to mock my clienta at all..... :-)

  • @v.n.7578
    @v.n.7578 Před rokem

    18 seconds since upload

  • @user-zk5ym9ut1j
    @user-zk5ym9ut1j Před rokem

    So much effort to mock stuff that shouldn't be mocked at all, because it's IO call...
    You'd never had this problem if there was typed API client wrapper doing work that can be and SHOULD be mocked in a first place.

    • @nickchapsas
      @nickchapsas  Před rokem

      The GitHubApiService is the wrapper

    • @user-zk5ym9ut1j
      @user-zk5ym9ut1j Před rokem

      @@nickchapsas I see but I really can't imagine a situation when you need to write unit tests for such class. It should be without any business logic ideally.

    • @PovilasPanavas
      @PovilasPanavas Před rokem

      This is not testing HttpClient. It's testing that HttpClient is being invoked corrctly. We do find quite a few bugs while writing these types of tests. For example, you must pass some headers to authenticate with server or pass information. One must also check it's GET, POST, PUT. All that needs checking.

  • @chswin
    @chswin Před rokem

    Or just abstract away the httpclient….?

    • @nickchapsas
      @nickchapsas  Před rokem +1

      How do you test the thing that abstracted the client away? You don’t? Then how do you know it works as expected?

  • @octavioarruda183
    @octavioarruda183 Před rokem

    I can't even mock httpclient, so this is not wrong at all

  • @Nirfust
    @Nirfust Před rokem

    The one time I needed to do this, I used fakes. A fake HttpMessageHandler class where inside its SendAsync method I called HttpRequestMessage.CreateResponse (with its request object parameter) with the statuscode and response object that I wanted, and then I created a fake htttpclient factory class that returned a new httpclient with the appropiate fake message handler

  • @shahzad.hassan
    @shahzad.hassan Před rokem +1

    Hi Nick, I am making another attempt to add a comment, as previous one was deleted by CZcams as you mentioned, as it had a link to a gist.
    Nick, excellent content as always, loved it. Thanks for that.
    I was wondering, why can't we use the Decorator pattern for this? So I can have an interface, IHttpMessageHandler, which implements the SendAsync method using the same signature as in the HttpMessageHandler.
    public interface IHttpMessageHandler
    {
    Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
    }
    Then you can create a custom message handler which inherits from HttpMessageHandler but takes the dependency on the above interface. It overrides the SendAsync method and calls the interface method instead.
    // using a decorator pattern
    public class CustomMessageHandler : HttpMessageHandler
    {
    private readonly IHttpMessageHandler _handler;

    public CustomMessageHandler(IHttpMessageHandler handler)
    {
    _handler = handler;
    }
    protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
    return await _handler.SendAsync(request, cancellationToken);
    }
    }
    Now you can mock the IHttpMessageHandler and set up the expectation of the SendAsync method. Next, new up the CustomMessageHandler and pass in the mock object of IHttpMessageHandler. Then new up the HttpClient using the CustomMessageHandler instance.
    After that, the mock of IHttpClientFactory can return the HttpClient created above.
    [Fact]
    public async Task SendAsync_Should_Return_403()
    {
    // Arrange
    var httpMessageHandler = new Mock();
    httpMessageHandler
    .Setup(x => x.SendAsync(It.IsAny(), It.IsAny()))
    .ReturnsAsync(new HttpResponseMessage(HttpStatusCode.Forbidden));
    var customMessageHandler = new CustomMessageHandler(httpMessageHandler.Object);
    var httpClientFactory = new Mock();
    httpClientFactory
    .Setup(factory => factory.CreateClient("GitHub"))
    .Returns(new HttpClient(customMessageHandler));
    var httpClient = httpClientFactory.Object.CreateClient("GitHub");
    var request = new HttpRequestMessage(HttpMethod.Get, "www.github.com");

    // Act
    var response = await httpClient.SendAsync(request, CancellationToken.None);
    // Assert
    response.StatusCode.ShouldBe(HttpStatusCode.Forbidden);
    }
    Please let me know what you think about this approach.

    • @Iingvarka
      @Iingvarka Před rokem +1

      I use exactly the same approach but use typed HttpClient instead of factory. Credit for the code in comments

    • @shahzad.hassan
      @shahzad.hassan Před rokem

      @@Iingvarka Yes, most of the times, I also use typed HttpClient but I have been using Refit lately. However, there are scenarios where you may need to inject the IHttpClientFactory, then the above approach works quite well.

  • @shahzad.hassan
    @shahzad.hassan Před rokem

    Nick, excellent content as always, loved it. Thanks for that.
    I was wondering, why can't we use a decorator pattern for this? So I can have an interface, IHttpMessageHandler, which implements the SendAsync method using the same signature as in the HttpMessageHandler.
    Then you can create a custom message handler which inherits from HttpMessageHandler but takes the dependency on the above interface and overrides the SendAsync method that calls the interface method.
    Now you can mock the IHttpMessageHandler and set up the expectation of the SendAsync method. Next, new up the CustomMessageHandler and pass in the mock object of IHttpMessageHandler. Then new up the HttpClient using the CustomMessageHandler instance, which will work as expected.
    I have created a gist here gist.github.com/softmatters/3a77b3ee0f204da7946a02f2e106fda3.
    Please let me know what you think about this approach.

  • @benrussill2667
    @benrussill2667 Před rokem

    Are you opposed to using the Assembly attribute { InternalsVisibleTo }
    Ie.
    [assembly: InternalsVisibleTo("MyApplication.Test")]

    • @nickchapsas
      @nickchapsas  Před rokem

      Absolutely not. In fact this is so funny. I have a video about all the ways you can use InternalsVisibleTo coming on Thursday

    • @benrussill2667
      @benrussill2667 Před rokem

      @@nickchapsas using this attribute it how I've always done unit tests for internal protected methods (unless making a concrete class from abstract is easy)... And private methods should be tested by all protected/public methods

    • @benrussill2667
      @benrussill2667 Před rokem

      @@nickchapsas Also: great videos and content. And thank you for your replies. It's always much appreciated!