How do I test a running API?
Hey, I'm using NUnit to test my application.
Now, my application project consists of two parts: The application itself and an API server.
I'm running a HttpClient.GetAsync command on the application using my localhost URL for the API.
var response = client.GetAsync("http://localhost:5255/api/product/sort="+ (int)sort +"&filter="+ (int)filter).Result;
I want to test this method or rather the API calls.
How do I do that? AFAIK I can't test when the application is running which I have to to get my API running?
I hope someone can help me. Thank you very much! 🙂34 Replies
First and foremost throw that
.Result
off the bridge and use proper async/await
Test the API as an API, not through the lens of the clientyou probably want TestServer
look it up
You want to mock API responses to test the client, and use integration testing with
WebApplicationFactory
to test the API
As a side note, use string interpolationI thought to test it in case the URL changes for example.
I have made 7 tests for the API itself.
Will do as well, thank you!
Hmm, I call a similar command within the constructor. How would I go about that?
Start by removing async code from the constructor
Then
await
the async callYeah but for that the method has to be async?
Yes
How would I async the constructor?
You would not
Long-running code should not be running in the constructor
Ah, yeah, makes sense.
I'll just create the object and call it afterwards.
(as a side note, you can safely depete the Newtonsoft dependency and just use the built-in JSON serializer)
What is the client, btw?
Some WPF app? A Blazor SPA?
A Blazor Web Application
Ah, that makes things simple
Use dependency injection
Create a product service/repository/whatever, that will have the
GetProductsAsync()
method that returns a List<ProductItem>
Inject the HttpClientFactory
into that
And inject that into whatever component needs those products
By injecting the client factory you get the benefit of every call being able to use the same URL
So should it change, you only change it in one place
You could also consider using a typed client, which would elimnate the need for a service/repo layer
And
Is how I have it right now.
Ah, huh, MVVM?
Can't say I ever used it with Blazor
I just try to have some sort of standard, not gonna lie. 😄
I'm not used to Blazor at all!
What's the
Refresh()
and StateHasChanged()
do?
Properties in Blazor are reactive by defaultThey get called within the home file.
Because otherwise when I tried to filter or sort the view it did not update.
is probably how I'd do it
If you need filtering or sorting, it would also be handled by that typed client/repo/service/whatever
Make
Load()
public, give it arguments what to sort by and filter by
Then call it from outside the component if need be
From your sort dropdown component or w/eSadly just saw that OnInitailized is getting called too late because the products need to be loaded into the grid before I load the page.
wtf why
System.NullReferenceException: "Object reference not set to an instance of an object."Because foreach'ing through the products throws me this error.
Ah, derp
There, solved
It will start as an empty list, not a null
Yeah, that works.
@ZZZZZZZZZZZZZZZZZZZZZZZZZ
One more question;
I'm perfectly fine not using async methods for sorting and filtering, right?
object
💀
And you have an await
here, so this method does have to be async
Also, I'd recommend doing the sorting and filtering on the database
Not on the data that was fetched from the db
Assuming Product.GetProductAsync()
gets the products from the database, that is
Ah, then that's fineIt's just a JSON, so I'm a bit limited. 😄
This yes, just thinking about the Sort and Filter methods.
Because I don't await those but could build them this way.
Do they do anything asynchronously?
Not really. Just wondering if it affects the API itself.
If a method does not
await
anything it does not need to be async
Alright, just thinking about performance. 😄
It's actually a project for a job interview so I want to be as precise as possible.
Though I'm a bit unsure what to return if not an object - because I want status codes but also content to be send back. x)
Should I build a wrapper around the objects to include the status code and the object?
ActionResult<List<Product>>
for example
Or even better, the typed result
Result<OkResult<List<Product>>, NotFoundResult>
As a side note, don't use StatusCode
when you're returning a common code
Return NotFound()
instead
Unauthorized()
instead of 505
, etcWhen it's async I'd need to wrap the result into a Task as well, right?
Task<Result<OkResult<List<Product>>, NotFoundResult>>
So something like
Yep
You can make it easier on yourself using a type alias
Actually
sort
and filter
will automatically bind to query parameters anyway
No need to make it a part of the pathAh, okay. Helps me a lot. Thank you!