You can write code in many different ways, some of them are more
testable than other, even though many of the less testable ways are not
bad or anyting like that. Like mutating a reference value like when
something takes a output pointer etc. Or having most of the code in the
None of these are “bad”. But it makes it harder to write unit tests for
If you think something is good, then try to make it as easy as possible
to do it.
I don’t do test driven development, because I don’t think it is the best
way to work. But I do think that writing unit and integration tests
should be a part of the process, because having good tests and coeverage
will save you time in the long run. And it is a must if you want to move
to the next level and get into automated deployments.
If you start with a typical C# .NET Core REST API. Then you could do
everything in the Controller. It would work well. And the code could be
clean. Probably a little or a lot of duplication of code but still it
The problem with this approach however is that there is nothing you can
unit test, because everything is tied together. Then you are limited to
What I usually do is that I take the Controller and I limit it to
validating input, checking permissions (ideally done with attributes and
filters) and calling a “service”.
The services takes input from the controller and is in charge of
checking all the right things, doing all the correct operations and
preparing the data structure the API should return.
Then all SQL stuff, and all the Redis stuff etc are put into
repositories. And the classes that takes data and turn into something
else are done in builder classes.
All of this are tied together with as many static methods as possible
(where it is possible) and dependency injection.
The advantage of this approach is that you can actually write tests for
the controller without it showing up in the database. And the same goes
for the service and the builders. Because you can just fake the
dependency injection crap.
If you want to have a project where most of the code is covered by
tests, then you need to write the code in a way where it is possible.