You are mocking the HttpClient the wrong way

แชร์
ฝัง
  • เผยแพร่เมื่อ 2 ก.ค. 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

ความคิดเห็น • 168

  • @nickchapsas
    @nickchapsas  2 ปีที่แล้ว +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 2 ปีที่แล้ว

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

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +4

      @@v.n.7578 I have made a video making my own mocking library that explains that here: th-cam.com/video/9kEURoqHKZ0/w-d-xo.html

    • @danutz_plusplus
      @danutz_plusplus 2 ปีที่แล้ว +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 2 ปีที่แล้ว

      @@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 2 ปีที่แล้ว

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

  • @RichardSzalay
    @RichardSzalay 2 ปีที่แล้ว +13

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

  • @alexanderkvenvolden4067
    @alexanderkvenvolden4067 2 ปีที่แล้ว +91

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

    • @paulrockerdale9409
      @paulrockerdale9409 2 ปีที่แล้ว

      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 ปีที่แล้ว

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

  • @nickchapsas
    @nickchapsas  2 ปีที่แล้ว

    Get started with Octopus Deploy: oc.to/nickchapsas

  • @RahulSingh-il1xk
    @RahulSingh-il1xk 2 ปีที่แล้ว +17

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

  • @stefanbogdanovic590
    @stefanbogdanovic590 2 ปีที่แล้ว +3

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

  • @aughey
    @aughey 2 ปีที่แล้ว +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 2 ปีที่แล้ว

      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.

  • @kaiserbergin
    @kaiserbergin 2 ปีที่แล้ว +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!

  • @judas1337
    @judas1337 2 ปีที่แล้ว +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.

  • @pablocom
    @pablocom ปีที่แล้ว

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

  • @strawhenge5007
    @strawhenge5007 2 ปีที่แล้ว +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.

  • @shadowsir
    @shadowsir 2 ปีที่แล้ว +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...

    • @sethreidnz1
      @sethreidnz1 วันที่ผ่านมา

      So that they can assert that the the code that actually uses the http client is correct forming the request? How do you know that that code is working?

    • @shadowsir
      @shadowsir วันที่ผ่านมา

      In our case, the request is VERY rarely more complex than "here's a json object, POST/PUT/PATCH it to or GET something from expect the result to be a json object" + possibly some code to fetch a token to put in the header + possibly an API key that also needs to go into the header.
      I guess the only thing we're not testing is that System.Text.Json or Newtonsoft.Json converts the object properly, but again, that's library code...
      Do you really need to mock the HttpClient just for that?

  • @Misterjuzz
    @Misterjuzz 2 ปีที่แล้ว

    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.

  • @vitaliykoritko5080
    @vitaliykoritko5080 2 ปีที่แล้ว

    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

  • @myemailvl
    @myemailvl 2 ปีที่แล้ว +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.

  • @Myuuiii
    @Myuuiii 2 ปีที่แล้ว

    Loving the content! Keep it up!

  • @nsedwards
    @nsedwards ปีที่แล้ว

    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

  • @SandGrainOne
    @SandGrainOne 2 ปีที่แล้ว

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

  • @nickst0ne
    @nickst0ne 2 ปีที่แล้ว

    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.

  • @7th_CAV_Trooper
    @7th_CAV_Trooper 2 ปีที่แล้ว +4

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

  • @Pookzob
    @Pookzob 2 ปีที่แล้ว +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  2 ปีที่แล้ว +1

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

    • @Pookzob
      @Pookzob 2 ปีที่แล้ว

      @@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 2 ปีที่แล้ว +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 2 ปีที่แล้ว +1

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

  • @user-xd7xm6gd2p
    @user-xd7xm6gd2p 2 ปีที่แล้ว

    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

  • @gavinlangley8411
    @gavinlangley8411 2 ปีที่แล้ว +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 ปีที่แล้ว +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 ปีที่แล้ว

      This is how i do it.

  • @evancombs5159
    @evancombs5159 2 ปีที่แล้ว +1

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

  • @paulrockerdale9409
    @paulrockerdale9409 2 ปีที่แล้ว

    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

  • @josda1000
    @josda1000 2 ปีที่แล้ว +2

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

  • @brianm1864
    @brianm1864 2 ปีที่แล้ว +3

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

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +1

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

    • @brianm1864
      @brianm1864 2 ปีที่แล้ว +1

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

    • @anthony8090
      @anthony8090 2 ปีที่แล้ว

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

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +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 2 ปีที่แล้ว

      @@nickchapsas fair enough

  • @narebinhaa
    @narebinhaa 7 หลายเดือนก่อน

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

  • @maikschonfeld5216
    @maikschonfeld5216 2 ปีที่แล้ว

    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  2 ปีที่แล้ว

      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 2 ปีที่แล้ว

      @@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.

  • @yoanashih761
    @yoanashih761 2 ปีที่แล้ว

    What is ILoggerAdapter?

  • @bhavikrupa9092
    @bhavikrupa9092 11 หลายเดือนก่อน

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

  • @jeroentje260
    @jeroentje260 2 ปีที่แล้ว

    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

  • @DoronGrinzaig
    @DoronGrinzaig ปีที่แล้ว +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.

  • @paulrockerdale9409
    @paulrockerdale9409 2 ปีที่แล้ว

    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

  • @kwibuske
    @kwibuske ปีที่แล้ว

    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  ปีที่แล้ว

      What we are testing is the facade service

  • @carljohnlopez5425
    @carljohnlopez5425 ปีที่แล้ว

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

    • @nickchapsas
      @nickchapsas  ปีที่แล้ว

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

  • @futurexjam2
    @futurexjam2 2 ปีที่แล้ว

    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.

  • @dukefleed9525
    @dukefleed9525 5 หลายเดือนก่อน

    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 ?

  • @Iingvarka
    @Iingvarka 2 ปีที่แล้ว

    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  2 ปีที่แล้ว

      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 2 ปีที่แล้ว +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  2 ปีที่แล้ว

      @@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 2 ปีที่แล้ว

      ​@@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 2 ปีที่แล้ว

      @@nickchapsas The solution that Igor suggested seems identical to what I suggested with the code, I think, and TH-cam 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.

  • @frankbanini8884
    @frankbanini8884 2 ปีที่แล้ว

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

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      Check the description

  • @jametime7491
    @jametime7491 2 ปีที่แล้ว +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  2 ปีที่แล้ว +3

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

    • @neppe4047
      @neppe4047 ปีที่แล้ว

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

  • @antonmartyniuk
    @antonmartyniuk 2 ปีที่แล้ว +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  2 ปีที่แล้ว

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

    • @rpm4598
      @rpm4598 2 ปีที่แล้ว

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

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

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

    • @sodreigor
      @sodreigor 2 ปีที่แล้ว

      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 2 ปีที่แล้ว +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

  • @snapching
    @snapching 9 หลายเดือนก่อน

    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

  • @joro550
    @joro550 2 ปีที่แล้ว +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 2 ปีที่แล้ว

      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.

  • @ArgeKumadan
    @ArgeKumadan 2 ปีที่แล้ว

    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  2 ปีที่แล้ว +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 2 ปีที่แล้ว

      @@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 :))

  • @zaoralj
    @zaoralj 2 ปีที่แล้ว

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

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

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

  • @codingbloke
    @codingbloke 2 ปีที่แล้ว +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.

  • @pilotboba
    @pilotboba 2 ปีที่แล้ว

    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  2 ปีที่แล้ว +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 2 ปีที่แล้ว +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.

  • @bramburn
    @bramburn 2 ปีที่แล้ว

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

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +1

      WebApplicationFactory is for integration testing. This is for unit testing

    • @bramburn
      @bramburn 2 ปีที่แล้ว

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

  • @Steven_Olson
    @Steven_Olson 2 ปีที่แล้ว

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

  • @tplummer217
    @tplummer217 ปีที่แล้ว

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

  • @shahzad.hassan
    @shahzad.hassan 2 ปีที่แล้ว

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

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

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

    • @shahzad.hassan
      @shahzad.hassan 2 ปีที่แล้ว

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

  • @marvinbrouwer459
    @marvinbrouwer459 ปีที่แล้ว

    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  ปีที่แล้ว

      Because it’s synchronous and it’s not used

  • @alirezanet
    @alirezanet 2 ปีที่แล้ว

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

  • @2SHARP4UIQ150
    @2SHARP4UIQ150 2 ปีที่แล้ว

    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  2 ปีที่แล้ว +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 2 ปีที่แล้ว

      ​@@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.

  • @fernandoluiz4593
    @fernandoluiz4593 ปีที่แล้ว

    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 ปีที่แล้ว

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

  • @teodorchirileanu
    @teodorchirileanu 2 ปีที่แล้ว

    wow nice tan!

  • @bilbobaggins8953
    @bilbobaggins8953 ปีที่แล้ว

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

  • @graycleary
    @graycleary 2 ปีที่แล้ว

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

  • @T___Brown
    @T___Brown 2 ปีที่แล้ว

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

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      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 2 ปีที่แล้ว +1

      @@nickchapsas why? I dont believe so.

    • @T___Brown
      @T___Brown 2 ปีที่แล้ว

      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 ปีที่แล้ว +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.

  • @benrussill2667
    @benrussill2667 2 ปีที่แล้ว +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)?

  • @ytxzw
    @ytxzw ปีที่แล้ว

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

    • @nickchapsas
      @nickchapsas  ปีที่แล้ว

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

    • @ytxzw
      @ytxzw ปีที่แล้ว

      ​@@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  ปีที่แล้ว

      @@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 ปีที่แล้ว

      @@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  ปีที่แล้ว +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.

  • @vmachacek
    @vmachacek 2 ปีที่แล้ว

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

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +1

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

  • @Nikkes02
    @Nikkes02 ปีที่แล้ว

    What if I need to mock a mockingbird?

  • @TangoMikeOscar
    @TangoMikeOscar 2 ปีที่แล้ว

    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  2 ปีที่แล้ว +1

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

    • @RaMz00z
      @RaMz00z ปีที่แล้ว

      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.

  • @bruno.arruda
    @bruno.arruda 2 ปีที่แล้ว

    This project hasn't been update for 3 years.

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +3

      HTTP hasn't changed in 10 years

    • @bruno.arruda
      @bruno.arruda 2 ปีที่แล้ว

      @@nickchapsas fair.

    • @RichardSzalay
      @RichardSzalay 2 ปีที่แล้ว +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.

  • @Lazzerman42
    @Lazzerman42 2 ปีที่แล้ว

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

  • @Anequit
    @Anequit 2 ปีที่แล้ว

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

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      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 2 ปีที่แล้ว

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

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +2

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

    • @Anequit
      @Anequit 2 ปีที่แล้ว

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

  • @DJTimeLock
    @DJTimeLock 2 ปีที่แล้ว

    Bold of you to assume i mock anything

  • @v.n.7578
    @v.n.7578 2 ปีที่แล้ว

    18 seconds since upload

  • @Nirfust
    @Nirfust 2 ปีที่แล้ว

    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

  • @user-zk5ym9ut1j
    @user-zk5ym9ut1j 2 ปีที่แล้ว

    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  2 ปีที่แล้ว

      The GitHubApiService is the wrapper

    • @user-zk5ym9ut1j
      @user-zk5ym9ut1j 2 ปีที่แล้ว

      @@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 ปีที่แล้ว

      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 2 ปีที่แล้ว

    Or just abstract away the httpclient….?

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว +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 ปีที่แล้ว

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

  • @shahzad.hassan
    @shahzad.hassan 2 ปีที่แล้ว

    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.

  • @shahzad.hassan
    @shahzad.hassan 2 ปีที่แล้ว +1

    Hi Nick, I am making another attempt to add a comment, as previous one was deleted by TH-cam 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 2 ปีที่แล้ว +1

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

    • @shahzad.hassan
      @shahzad.hassan 2 ปีที่แล้ว

      @@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.

  • @benrussill2667
    @benrussill2667 2 ปีที่แล้ว

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

    • @nickchapsas
      @nickchapsas  2 ปีที่แล้ว

      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 2 ปีที่แล้ว

      @@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 2 ปีที่แล้ว

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