How to unit test Minimal APIs in .NET 6 (and why it's hard)

preview_player
Показать описание

Hello everybody I'm Nick and in this video I will show you how you can properly unit test Minimal APIs in .NET 6. There has been a few blogs going around showing what I consider to be a bad practice so I'd like to give you my take on the matter and show you why those claims are wrong and how I would unit test them myself.

Don't forget to comment, like and subscribe :)

Social Media:

#csharp #dotnet #minimalapi
Рекомендации по теме
Комментарии
Автор

Just to clear something out. I am not saying that you should only write unit tests for your endpoints or that you shoulnd't be writing integration tests. This video isn't about that.
All I am saying is that IF you wanted to write unit tests for your endpoints then you SHOULD be able to do that, which as it currently stands, you can't without hacking it and that calling integration tests "unit tests" just because unit testing isn't possible, is just false.

nickchapsas
Автор

Nice video! Like it when you draw a very clean line between unit tests and functional tests / integration tests.

CodewithSaar
Автор

You are doing great work. Was trying to do unit tests for the minimal API as well and not succeeding.

OlleHellman
Автор

Great video with some fascinating points raised for those who want to unit test their min apis. I agree that this style of testing should not be referred to as unit testing. I don't think I have written a unit test for a HTTP API request handler for close to 8yrs, starting with the NancyFX TestServer, then in MVC apps with the OWIN TestServer and now in .Net Core with the WAF. I prefer to invoke the whole request pipeline so I can test things like validation and auth. I don't call these unit tests but component tests because they would test the E2E side effects of the service, mocking the external service dependencies.

ritasker
Автор

Great content Nick. I faced the same problem recently. Your video helped me a lot.

I am always looking for 100% test coverage, even with some developers saying it’s not needed. The framework should always provide APIs that are testable.

gustavo-santos-dev
Автор

Hi Nick, found this after asking on the other video. Great temporary solution until .Net 7 is released. I now have this integrated and it's working well.

MicroFourThirdsCorner
Автор

I'm not at all shocked with your reflection solution. It's encapsulated and when (hopefully) the API is improved, you'll be able to refactor without changing anything else.
It seems the real problem here is really the MS presentation you witnessed and the desire to unit test (in isolation) as you mentioned several times.
I've been experimenting with service tests via the WAF and that stuff works super well. It requires a little work to abstract certain things as I prefer my tests to be smaller rather than having irrelevant boiler plate e.g. json deserialization, etc but it seems to me much more valuable because they test more at a much lower cost. I like to go with a diamond test strategy as opposed to a pyramid. Talk for another day. Good video 👍

fabiomilheiro
Автор

Hey Nick, Love your content. Do you recommend any reading materials for improving my dotnet/software development skills?

mikejay
Автор

I’d love to see a video about hexagonal testing api. What do you mock and why ? The philosophy about “the less mocking the better” and calling it “unit” / “integrated” testing…
I’m confusing my team sometime with those concept.

clementdurazzo
Автор

Great video as always! When you say several times it is annoying, seems like it was about VS :)

kipsiokas
Автор

Good show case on how to set it up and good video as always... but I don't share your opinion/definition on unit tests. I mean what is a unit? That really depends on who you talk to, so context matters. If you look at it from the perspective of business value I really think the application is the unit and then this is actually fine. All to often I see people doing "proper" unit testing and they basically mock everything that builds up the actual application logic so you start testing your mocks which is completely backwards. I would prefer to see a minimal usage of mocks... but that is my opinion :). Great content!

TomasJansson
Автор

It's amazing to me how they created something pretty neat (minimal apis) and made it a hassle to use properly. Validation is a pain but can be circumvented and testing also seems to be an after thought. I'm not a C# dev, but I've a couple projects with the minimal API and I like the principle there's a lot of weird oversights. Maybe these things will improve in the future though.

roccociccone
Автор

@Nick I agree with you on this one. keep up the good work!!

davidchen
Автор

At this point I would probably write some kind of injectable interface „IResultFactory/Builder” which would have mocked methods Ok/NotFound - and avoid using of the Results class directly. Real world object (not mocked) would call MS methods. Not the most elegant way of doing things but reflection is no longer needed.

mikeleg
Автор

What’s the value in unit testing a minimal API when all it should be doing is passing messages to whatever handles the business logic?

lawrencejob
Автор

Testing a controller action like this is akin to writing a unit test that verifies that a constructor doesn't return a null (yes, I have seen several unit tests that do exactly that!)
Code coverage requirements tend to force developers to write "useless" unit tests just to check the box.

markcooke
Автор

Perhaps instead of using Reflection, one can use dynamic? Especially if many tests have to run, the clr/dlr should cache callsites and all to reduce the drag on overall performance.

But I do think exposing the concrete IResult classes is the way to go.

alexisfibonacci
Автор

If you you used MediatR to dispatch commands/queries you could test that as unit test. Controller or minimal api func should just pass a message to a handler INMHO. Also, don't buy your definition of "unit" test. That test is unit test, as it tests unit of work. I prefer to talk about solitary and sociable tests, and prefer to test code as close as possible as it will run in production.

edvardpitka
Автор

Nick... I've got a couple notes. And before you say, "This is just sample code." I want to assert that your code is actually a very accurate representation of good production code. Your video is correct on all its points, but part of the premise is misleading.

Firstly, your APIs are just directly calling the repository. It indicates there is no business logic, but no big deal, it's common enough. The main thing is that your Unit Tests are Mocking that repository. So you COULD re-write your Unit Test like so:

public void {
Customer cust = null;
Assert.AreEqual(null, cust);
}

Is that useful? Of course not. You may argue that you are testing the "logic" in the API endpoint, not just the mocked customer, which essentially says:

if (customer is null)
return NotFound();
return Ok();

What you really have there is a Guard Clause. The issue with "Unit Testing" a Guard Clause is twofold. (1) The thing you're REALLY testing is the return of some other method... so just test that other method directly. (2) There is no Conditional Transformation. It's just a Conditional and a Return. That means your Unit Test code will look identical to your Implementation Code, which means the test doesn't add value.

The Kicker: The reason people test their API endpoints in a "UnitTest project" (obviously an Integration Test as you point out) is for the exact purpose of going through all the middleware. However, that is such a waste of time, as you point out. Getting to the point of ensuring your whole Web API pipeline is fully tested in a "UnitTest Project" is equivalent to testing that DateTime.Now works correctly, or that IIS works correctly. You shouldn't have to do focused testing on tertiary systems unrelated to the goal of testing the current solution. Either you trust Microsoft (or whatever third party you use) or you don't. The way those pipelines get tested is during an external type of Integration Testing called System Testing, which are initiated externally after build, not during in a "UnitTest Project".

There is NO reason to test an API Endpoint from a "UnitTest" project. If you do end up having Business Logic in your API endpoint, that should be pulled back into a Domain Service. Because API Endpoints are essentially just a routing mechanism. They may call some other DTO method to get the Body or QueryParams into a nice format, but then essentially just call a Domain Service (or directly to the repo sometimes). And though an Exception Filter or a later Middleware should handle oddball things like NULL, at worst an API Endpoint will do a Guard Clause as you have shown here.

TLDR; There is no reason to test an API endpoint from a "UnitTest Project", even if you appropriately call it an "Integration Test". API Endpoints should be tested as part of System Testing, or perhaps from targeted external Integration Tests from PostMan or something. The solution to the testing here is to just write tests directly against your Domain Services and Repos. We don't have to test Microsoft's Web API. That's their job.

Suamere
Автор

U should probably do plural sight course putting all this concept into one .

Lot of recent .net changes and content is missing in plural sight.

As always great concepts and explanations.

mahesh_rcb