Fixes #1516 and #1631 : Allows @Spy with @InjectMocks to be injected into other @InjectMocks #1711
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
[This PR is a cherry pick of #1710 to release/3.x]
check list
including project members to get a better picture of the change
commit is meaningful and help the people that will explore a change in 2 years
Fixes #<issue number>
in the description if relevantFixes #<issue number>
if relevantThis PR aims to fix #1516 and #1631. I know and understand dependency injection is not priority of Mockito team but discussion on #1518 convinces me to propose a fix. Like @mockitoguy I think DI in Mockito is useful and most of reported issues denote users high expectations for a helpful feature rather than the fact it's broken.
Basically this PR allows fields annotated with @SPY and @Injectmocks to be injected into other fields annotated with @Injectmocks and so on.
It may also be a response to #174, the need to a @real annotation, actually I think most usage of @SPY and @Injectmocks combination is a workaround to such annotation.
Because PR ended to change a bunch of classes, I will highlight main changes.
"Entry point" of changes is InjectingAnnotationEngine, I add a loop of mock injection. The loop uses variants of existing field injection strategies documented in DefaultInjectionEngine.
To facilitate field injection strategies variants (StrictConstructorInjection and LenientPropertyAndSetterInjection), I merge ConstructorArgumentResolver (contract to find constructor arguments) and ConstructorInstantiator (contract to find and instantiate constructor) interfaces into an unique ConstructorResolver interface representing a strategy to find a constructor and its arguments. Constructor instantiation part comes back into FieldInitializer.
The fact to merge these two interfaces into ConstructorResolver leads to a better separation of concerns between finding constructor and its arguments in one side and instantiation, initialization and field injection on the other side. isResolvable() allows some tuning between the inclination of strategy implementations to fail with exception or handle failure softly. Moreover it's opening future smarter behaviors, for example BiggestConstructorResolver could try to resolve biggest constructor matching actual available mocks.
I hope you will appreciate this work.