Unit Testing Classes with Dependency Injection (ASP.NET Core)
How do you guys usually handle this? I saw some people mock every single injection which seems pretty horrible, other people end up in a way where they effectively have to rebuild the Program.cs class in their test project.
I'm using xUnit
To be a little more clear. The class I want to test on takes in some interfaces via dependency injection in it's constructor, and these are used in the methods I want to test. - Ideally, I want them to function how they actually would, using the concerete classes injected
33 Replies
If you want to use the real implementations, then do that.
Do what? Rebuild Prpgram.cs?
no, use teh real implementations
you could assemble a serviceprovider based on the real one from program if you want, or you just do
var sut = new Sut(new dep1, new dep2)
etc if thats feasible
it all depends on your setup and how complicated your dependency graph is
the reason mocking all dependencies is common is because
* its easy
* it makes your tests true unit tests (testing a distinct "unit" of code)Well those interfaces, the real implementation might also take some interfaces. And if I swap the concrete class I’m using for something I don’t want to have to go through every unit test and change it manually.
As far as mocking each interface, I’d be okay with it, but then if I change the way that method works I’m again having to go to each unit test and change it
And one of the interfaces is a mapper, so any change to the object I’m mapping and I’ll have to change them all etc
Well those interfaces, the real implementation might also take some interfacesSure, so use dependency injection to resolve your service under test?
Yeah I was just checking there wasn’t some simpler way people used but it seems like this is still the best
honestly if you want to test like this (which is perfectly fine btw), I'd consider using WebApplicationFactory and TestingContainers (for a database or similar) and making full on integration tests
why stop half the way there 🙂
I mean, these should just be unit tests
they are not
if you are testing a service that has real dependencies that do actual work, thats no longer a unit by most definitions
"Half my codebase is one unit" is a weird border
if a single test "tests" a huge portion of your app, thats really close to a full E2E or integration test already
I mean I would mock them if it weren't such a pain to do so
but I'd say that if it's still internal to the project, and not using the more external stuff like a database, I'd still think of it as a unit test
these are just terms for distinction btw, you can still use xUnit to make e2e or integration tests
it's not using a huge portion at all
it's basically using a helper method
it's using a mapper
right
it's just that mocking the mapper is probably going to cause more pain down the line if I change the mapper or the object coming out
hm
maybe I should just mock it anyway
mocking a mapper does indeed sound painful
Then again
it would make it more of a unit test you are right there, since rn it would effectively be testing the mapper
I very rarely if ever use mappers in a service
I prefer to do that at the endpoint level
the service/command/etc is part of the domain, so it operates on domain objects
your opinion might vary, and thats fine too 🙂
oh I'm probably just naming stuff wrong tbh
I don't think you are
but perhaps 🙂
I have the API, which is made up of the controller method -> service layer (handles business logic and calls mapper service) -> data access layer (contains no business logic)
thats exactly what I assumed yes
I don't do mapping in the service layer
its not a service concern, imho
its an API concern
I could see a world where you reuse your domain/data/service layers for lets say a console app, and you want a different shape on the resulting data
would you not test your controller method though?
not via a unit test
integration test, maybe
but since my controllers are literally just "model bind a http request, issue a command based on that data, map result, return result"
its not really a huge consideration
every single command (or service, in your case) is ofc tested
yeah mine is that without the mapping lmao
and I usually have tests for my mappers too, if they are not trivial
not to mention, Im leaning more and more towards static mapping methods these days
hm, okay for now I think I'll mock the mapper, in reality I won't end up changing stuff a huge amount for it to be a pain, and I really don't like the idea of not mocking it, and then this unit test testing other units...you've convinced me
AutoMapper etc is just more problem than its worth to me 🙂
I made my own static mapper so yeah
nice
you know what you could do?
idk how you currently build your services, but its somewhat common to have a "ConfigureServices" method that just takes an
IServiceCollection
in and works on that
when that method is done, its still a servicecollection, aka mutable
so you could use the real DI setup, modify the bits you need (change what mapper you use, or change the database connection etc) then build a provider for tests
then use that provider to resolve your services/dependencies for testing, often done by a "fixture" in most test frameworkshonestly man I'm going to mock it
you totally convinced me when you pointed out that just using the service means I'd be testing the mapper method when testing this method
if I have a unit test for this method I just want it testing this method
Go for it, see how it feels
well thanks again, talking it through really helped a lot
👍