Hi,
let's consider that I forgot to add @Autowired
in the below:
@SpringBootTest
public class VisitServiceTest {
private final VisitService visitService;
private final ApplicationContext applicationContext;
//@Autowired
public VisitServiceTest(VisitService visitService, ApplicationContext applicationContext) {
this.visitService = visitService;
this.applicationContext = applicationContext;
}
}
Since @Autowired
has to be explicit in case of constructor injection in a JUnit Jupiter test, I am getting the following error message, which is a bit hard to understand, especially for beginners:
org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [com.petclinic.core.VisitService visitService] in constructor [public com.petclinic.core.VisitServiceTest(com.petclinic.core.VisitService,org.springframework.context.ApplicationContext)].
I wonder if it would be possible to catch the exception first before it goes to JUnit, and add something like that:
Did you forget to explicitly add @Autowired above your constructor?
Thanks, and have a great day!
Comment From: sbrannen
Hi @michaelisvy,
I wonder if it would be possible to catch the exception first before it goes to JUnit, and add something like that:
No, that's unfortunately not possible.
JUnit Jupiter's internal infrastructure (specifically InterceptingExecutableInvoker.invoke(Constructor<T>, Optional<Object>, ExtensionContext, ExtensionRegistry, ReflectiveInterceptorCall<Constructor<T>, T>)
) attempts to resolve parameters for the test class constructor outside any custom interceptor (i.e., a custom InvocationInterceptor.interceptTestClassConstructor(...)
implementation).
Consequently, the SpringExtension
has no means to intercept the ParameterResolutionException
you've encountered.
Since
@Autowired
has to be explicit in case of constructor injection in a JUnit Jupiter test
That's actually not entirely true. 😉
@TestConstructor
can be used to make @Autowired
and @Inject
unnecessary on a test class constructor. For more information, check out the reference manual.
For example, annotating your test class (or one of its superclasses or implemented interfaces) as follows allows the test to pass without @Autowired
on the constructor.
@TestConstructor(autowireMode = ALL)
Similarly, adding the following to your junit-platform.properties
or spring.properties
file (or setting it via SpringProperties
or a JVM system property) also allows your test to pass without @Autowired
on the constructor.
spring.test.constructor.autowire.mode = all
In light of the above, I am closing this issue.
Cheers,
Sam
Comment From: michaelisvy
thanks a lot @sbrannen for the super-clear response. I learned something new today :)
Comment From: sbrannen
thanks a lot @sbrannen for the super-clear response.
You're welcome.
I learned something new today :)
That's always a good thing. 👍
I also learned something new, namely that there's apparently no way for an extension to catch a ParameterResolutionException
thrown while resolving arguments for a test class constructor, but I'll likely investigate/discuss that further within the JUnit team.