C
C#12mo ago
illunix

❔ How to mock HttpClient that is automatically applied in class without IHttpClientFactory

Hello, I have a problem because I don't know how can I mock HttpClient in my tests for StripeClient, I don't use IHttpClientFactory, HttpClient is assigned automatically
public sealed partial class StripeClient : IStripeClient
{
private readonly HttpClient _http;
}
public sealed partial class StripeClient : IStripeClient
{
private readonly HttpClient _http;
}
services.AddHttpClient<IStripeClient, StripeClient>(...)
services.AddHttpClient<IStripeClient, StripeClient>(...)
50 Replies
mtreit
mtreit12mo ago
You can mock the HttpMessageHandler as described here: https://stackoverflow.com/questions/36425008/mocking-httpclient-in-unit-tests
Stack Overflow
Mocking HttpClient in unit tests
I have some issues trying to wrap my code to be used in unit tests. The issues is this. I have the interface IHttpHandler: public interface IHttpHandler { HttpClient client { get; } } And the ...
illunix
illunix12mo ago
Is it will mock HttpClient specific for StripeClient? Using MockHttpMessageHandler
mtreit
mtreit12mo ago
I don't know anything about StripeClient
illunix
illunix12mo ago
I think I provided everything you need to know
mtreit
mtreit12mo ago
Just showing that you can construct an HttpClient that will call into your mock message handler.
illunix
illunix12mo ago
I mean is it create http client mock with this configuration for example
services.AddHttpClient<IStripeClient, StripeClient>(q =>
{
q.BaseAddress = new("https://api.stripe.com/v1/");
q.DefaultRequestHeaders.Authorization = new(
"Bearer",
stripeOptions.ApiKey
);
}
services.AddHttpClient<IStripeClient, StripeClient>(q =>
{
q.BaseAddress = new("https://api.stripe.com/v1/");
q.DefaultRequestHeaders.Authorization = new(
"Bearer",
stripeOptions.ApiKey
);
}
Okey, but I want create a mock of http client specific for that that I show
mtreit
mtreit12mo ago
I think you would need to not use AddHttpClient if you want to mock it
illunix
illunix12mo ago
I want use AddHttpClient Is there no way to do this?
mtreit
mtreit12mo ago
I don't think so
illunix
illunix12mo ago
Mhm Is smth like that is okey?
[Test]
public async Task Test()
{
// Arrange
var mockHttpClient = new HttpClient(_handlerMock.Object);

mockHttpClient.BaseAddress = new Uri("https://api.stripe.com/v1/");

var stripeClient = new StripeClient(mockHttpClient);

// Act
var response = await stripeClient.GetProducts();

Assert.NotNull(response);
}
[Test]
public async Task Test()
{
// Arrange
var mockHttpClient = new HttpClient(_handlerMock.Object);

mockHttpClient.BaseAddress = new Uri("https://api.stripe.com/v1/");

var stripeClient = new StripeClient(mockHttpClient);

// Act
var response = await stripeClient.GetProducts();

Assert.NotNull(response);
}
mtreit
mtreit12mo ago
I personally wouldn't even bother with that kind of a unit test (what is it actually testing) but I don't see anything wrong with the code.
illunix
illunix12mo ago
Its not completed yet, i want test If it returns expected product list. Is that make sense to create test for something like that?
mtreit
mtreit12mo ago
As long as you are testing your actual code somehow and not just testing the mock, that's fine. I'm kind of anti-unit-test so take my opinions on the topic with that in mind.
illunix
illunix12mo ago
Testing the mock? Im not testing the mock I create a new instance of my stripe client, and from what I understand you are not fan of writing unit tests right?
mtreit
mtreit12mo ago
Unit tests are fine for regression testing, so if you find a bug, it's a good practice to add a unit test to ensure that bug never comes back. For verifying basic functionality, I much prefer end-to-end functional tests. I think most unit tests are a waste of time. But I know a lot of developers love them so do whatever makes you feel good 🙂 There is a classic essay on this topic that I think more developers should read and think about: https://rbcs-us.com/documents/Why-Most-Unit-Testing-is-Waste.pdf
illunix
illunix12mo ago
I hate unit testing and i never write them, and I never know when should I write it, I mean for that method of something What is end to end tests? @mtreit
mtreit
mtreit12mo ago
Like, testing the final running program. No mocks. Testing the real thing. I was a professional software tester for years and my opinions are colored by my belief that the point of software testing is to find bugs, and tests that never find bugs and almost certainly never will find bugs are just a complete waste of everyone's time.
illunix
illunix12mo ago
Yeah you are completely right, I never thought like this before
mtreit
mtreit12mo ago
Most software developers do not agree with this point of view
illunix
illunix12mo ago
But what is that e2e tests What is about Is about for example testing Is request to my api was successfull?
mtreit
mtreit12mo ago
So that's what most developers do - test the happy path. But wouldn't you have already tested that the code works before you even commit it? Wouldn't you have stepped through the code line by line as you were developing it to verify it was correct? (Ideally the answer should be yes.) So if the code is known correct, what value does writing an automated test have? Well, the value is that if you later break that code, you will find out because the test failed. But basic "does my code work" tests are usually unlikely to find bugs. Most of the time if the code is just fundamentally broken you will certainly discover that because other more interesting tests will also fail. So good testing focuses on things that are more likely to find bugs. Those kinds of things are: Stress testing Performance testing Fuzzing / security testing Testing boundary conditions (maximum possible input size, minimum possible input size, negative values, null values, empty strings, etc., etc., ) That kind of thing.
Florian Voß
Florian Voß12mo ago
no you don't want that. the idea of mocking is so that you can work with objects seperated from your actual application. When you use AddHttpClient() that registers it in the ServiceCollection of your app and hence make it part of your app
mtreit
mtreit12mo ago
Beat the crap out of the software and see where it breaks is what you should ideally be doing 🙂 One of my favorite forms of testing is long-haul stress testing. Hammer the code in parallel from many clients (I work on web services) and let that run for 24 hours (on the Windows team we used to run for a week) and see if the software crashes or otherwise fails. (This kind of testing is also just fun!)
illunix
illunix12mo ago
So I should not write e2e test for every request in my api The test types that you mention I didn’t know they exist @mtreit
mtreit
mtreit12mo ago
You should test every API thoroughly
illunix
illunix12mo ago
Without writing tests That’s how I worked all the time
mtreit
mtreit12mo ago
If you do something like write a stress test (I'm going to make 10,000 calls in parallel and I expect all of them to succeed) you will implicitly verify the happy path. No, you should write tests. Just write good tests. That are likely to find bugs if those bugs exist.
Florian Voß
Florian Voß12mo ago
Here is my perspective on unit testing tho: TDD is not all about preventing bugs preemptively, it seems like more of a design decision because it forces you to follow good design when you have to write code that makes your unit tests pass. As in following SOLID and other principles
mtreit
mtreit12mo ago
I'm in the Clean Code sucks and TDD is crazy camp, but I respect your opinion 🙂
Florian Voß
Florian Voß12mo ago
have you considered both the london and chicago school?
illunix
illunix12mo ago
Clean code isn’t clean
Florian Voß
Florian Voß12mo ago
they are very different as in what they consider a unit test or integration test in the first place
mtreit
mtreit12mo ago
I don't know what that refers to. I just know that most unit tests are a waste of time.
illunix
illunix12mo ago
Okey so what things in normal Api should I test because I don’t see anything, 99% of all my stuff that I write is crud And external api calls
mtreit
mtreit12mo ago
That's really up to you.
illunix
illunix12mo ago
I like your opinion on testing that’s why I ask
mtreit
mtreit12mo ago
Whatever you think is most likely to catch bugs that get introduced down the road. Like I said, I would write tests that try to make the program crash. When it doesn't crash, you have higher confidence that the code is solid. Here's a real-world example of a test I was running earlier this week (this is a PowerShell script)
(0..1000) | Foreach -Parallel {(Invoke-WebRequest "https://localhost.something.com:8080?ssrenable=true&ssronly=true&apiversion=v2" -Headers $headers)}
(0..1000) | Foreach -Parallel {(Invoke-WebRequest "https://localhost.something.com:8080?ssrenable=true&ssronly=true&apiversion=v2" -Headers $headers)}
When I ran this test against the service it is testing, it found a memory leak. Also, about 20% of the calls fail with HTTP 500. That means there's a bug in the service code somewhere. (Still need to track that down.) But it's a good example of an actual functional test finding real-world bugs. Unit tests don't find those kinds of bugs.
mtreit
mtreit12mo ago
There are also tools like this that can be useful: https://github.com/codesenberg/bombardier
GitHub
GitHub - codesenberg/bombardier: Fast cross-platform HTTP benchmark...
Fast cross-platform HTTP benchmarking tool written in Go - GitHub - codesenberg/bombardier: Fast cross-platform HTTP benchmarking tool written in Go
illunix
illunix12mo ago
So should I create test like this powershell script for every request in my api that I have? Also I don’t understand how is it possible that 80% requests that was successful but 20% not @mtreit
mtreit
mtreit12mo ago
Oh it's very possible. Multi-threading race condition bugs for instance. For automated tests that are part of your CI pipeline I would use a test framework (like a unit test framework is fine) that can run tests against the running version of your service. My PowerShell script example was specifically to try to reproduce the memory leak, but the basic idea: make a bunch of parallel calls to the service and verify they all succeed is a good idea to do for any web methods.
Unknown User
Unknown User12mo ago
Message Not Public
Sign In & Join Server To View
illunix
illunix12mo ago
Mhm, but for example how do you solve problem like this if logic is correct, I don’t understand that part I didn’t even know it’s possible
mtreit
mtreit12mo ago
What do you mean?
illunix
illunix12mo ago
I mean for example that 80% requests are successful but 20% was unsuccessful as you said, but why this 20% was unsuccessful and how did you solved that @mtreit
mtreit
mtreit12mo ago
Well, the next step would be to debug exactly what's happening on the server when the 500 happens. Possibly by adding more tracing, possibly by using a debugger to see what exceptions are being thrown.
illunix
illunix12mo ago
I just don’t understand the part why 80% work if 20% does not work, if 20% fail why not 100% 🤔
mtreit
mtreit12mo ago
Race conditions are a possibility Like two threads modifying the same shared state at the same time in a non-thread-safe way Sometimes you have cases where 1 call out of a million fails due to a timing issue like that. Those are much harder to debug
illunix
illunix12mo ago
That’s sounds complex I didn’t know that problem like this can happen
boiled goose
boiled goose12mo ago
why would you mock HttpClient
Accord
Accord12mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server
More Posts