I solved this with a test helper method that creates a fully mocked instance and returns a struct with the mocked instance and all the mocks that it consumes. Unit test setup starts by getting a new instance and overriding the mocks that it cares about. Now constructor breakage is isolated to fixing the default mocks in the helper method.
Maybe I should write this up somewhere.
Re:.NET Myths Dispelled
by DeathArrow on Sunday March 13, 2022 @09:32AM
(#30661047)
>Maybe I should write this up somewhere.
Please do, as it sounds interesting.
Re:.NET Myths Dispelled
by spaetzleesser on Sunday March 13, 2022 @08:30AM
(#30660666)
I did that too and it should be the default. Constructor injection is a bad pattern.
What do you mean by "constructor injection"?
Re:.NET Myths Dispelled
by spaetzleesser on Sunday March 13, 2022 @12:38PM
(#30662922)
In .NET a lot of DI is done by adding another interface to the constructor. So if you need some service way down the stack you add it to the constructor. This then in turn can require adding this dependency to all the tests that use this service.
Comments like these really amaze me. What sort of competent editor cannot handle such simple refactorings?
My comment describes a way to organize unit tests to work around this issue.
Re:.NET Myths Dispelled
by hackerfromthefu on Monday March 14, 2022 @07:18AM
(#30671004)
Maybe but in Blazor you have the choice of Property or Constructor DI. This choice is in all the major DI container libraries I've worked with in .NET, around a dozen over the years.
We use a tool called AutoFixture to automatically generate objects being tested. It will automatically mock constructor dependencies, so a change like you described doesn't require any test changes unless the new mock requires some setup for the test to pass.
Sorry, if tests are not adaptable to changing code, why are they called tests?
I thought tesring was to check software,not be a constraint on software development.
Also, I think using DI in the test process itself will mitigate the issue.
Re:.NET Myths Dispelled
by spaetzleesser on Sunday March 13, 2022 @08:29AM
(#30660657)
Some tests are not adaptable to changing code because of the way MS uses DI. A lot of DI is done by adding new parameters to the constructor.
It’s the same with async. Needing an async function somewhere can result in a huge cascade of changes.
Re:.NET Myths Dispelled
by culturedsystems on Sunday March 13, 2022 @10:19AM
(#30661413)
Constructor inject is generally a positive here, though, as the compiler will tell you where you need to add the new dependency. If you find that you have to add the dependency in lots of places just to satisfy the compiler, not because the functionality actually requires the dependency, that's usually a sign the class should be broken up into classes with more clearly defined responsibilities.
Re:.NET Myths Dispelled
by spaetzleesser on Sunday March 13, 2022 @12:41PM
(#30662965)
“If you find that you have to add the dependency in lots of places just to satisfy the compiler, not because the functionality actually requires the dependency, that's usually a sign the class should be broken up into classes with more clearly defined responsibilities.”
Sure in theory this is correct but you can’t always anticipate future needs. The class may still have very clearly defined responsibility but it just needs another piece of information that you can get only with DI. I feel this over dependence on DI in .NET forces you to design around the framework and not around what makes sense.
Re:.NET Myths Dispelled
by spaetzleesser on Sunday March 13, 2022 @08:24AM
(#30660629)
I have seen that too. They do way too much DI.
Sure, but there is a downside to it. You want to add a feature to the class that uses DI? Great, just add an injected object to the constructor. Except now a 100 unit tests broke because you changed the constructor. A 10 minute functionality change turns into a massive cut and paste operation in your Tests project.