为什么@SpringBootTest在构造函数注入中需要@Autowired
Why does @SpringBootTest need @Autowired in constructor injection
一个更笼统的问题。如果在常规 Spring 托管 class 中使用构造函数注入,则 classes 无需 @Autowired 注释即可自动装配,即。即:
@Service
class MailService(
private val projectService: ProjectService,
private val mailer: Mailer
) { ... }
在@SpringBootTest class中遵循相同的构造函数注入原则,您需要将@Autowired注解设置为构造函数参数,否则将无法注入class, 一世。即:
@SpringBootTest
internal class MailerTest(
@Autowired private val mailer: Mailer
) { ... }
为什么会出现这种差异?
在 Spring 启动应用程序的情况下,spring 负责连接 bean。
对于 JUnit 5,由 Spring 管理的 Beans 必须注入由 JUnit 管理的测试实例 class。幸运的是,JUnit 5 提供了一种通过 ParameterResolver.
来做到这一点的方法
@SpringBootTest
注册 SpringExtension,除其他功能外,它还用作 ParameterResolver:
@Override
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
Parameter parameter = parameterContext.getParameter();
Executable executable = parameter.getDeclaringExecutable();
Class<?> testClass = extensionContext.getRequiredTestClass();
PropertyProvider junitPropertyProvider = propertyName ->
extensionContext.getConfigurationParameter(propertyName).orElse(null);
return (TestConstructorUtils.isAutowirableConstructor(executable, testClass, junitPropertyProvider) ||
ApplicationContext.class.isAssignableFrom(parameter.getType()) ||
supportsApplicationEvents(parameterContext) ||
ParameterResolutionDelegate.isAutowirable(parameter, parameterContext.getIndex()));
}
ParameterResolutionDelegate.isAutowirable
依靠注解来确定是否可以从 Spring 的 ApplicationContext
中注入参数
public static boolean isAutowirable(Parameter parameter, int parameterIndex) {
Assert.notNull(parameter, "Parameter must not be null");
AnnotatedElement annotatedParameter = getEffectiveAnnotatedParameter(parameter, parameterIndex);
return (AnnotatedElementUtils.hasAnnotation(annotatedParameter, Autowired.class) ||
AnnotatedElementUtils.hasAnnotation(annotatedParameter, Qualifier.class) ||
AnnotatedElementUtils.hasAnnotation(annotatedParameter, Value.class));
}
事实上,如果省略@Autowired注解,JUnit会抱怨缺少ParameterResolver:
org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [test.Mailer mailer] in constructor [public test.MailServiceTest(test.Mailer)].
一个更笼统的问题。如果在常规 Spring 托管 class 中使用构造函数注入,则 classes 无需 @Autowired 注释即可自动装配,即。即:
@Service
class MailService(
private val projectService: ProjectService,
private val mailer: Mailer
) { ... }
在@SpringBootTest class中遵循相同的构造函数注入原则,您需要将@Autowired注解设置为构造函数参数,否则将无法注入class, 一世。即:
@SpringBootTest
internal class MailerTest(
@Autowired private val mailer: Mailer
) { ... }
为什么会出现这种差异?
在 Spring 启动应用程序的情况下,spring 负责连接 bean。
对于 JUnit 5,由 Spring 管理的 Beans 必须注入由 JUnit 管理的测试实例 class。幸运的是,JUnit 5 提供了一种通过 ParameterResolver.
来做到这一点的方法@SpringBootTest
注册 SpringExtension,除其他功能外,它还用作 ParameterResolver:
@Override
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
Parameter parameter = parameterContext.getParameter();
Executable executable = parameter.getDeclaringExecutable();
Class<?> testClass = extensionContext.getRequiredTestClass();
PropertyProvider junitPropertyProvider = propertyName ->
extensionContext.getConfigurationParameter(propertyName).orElse(null);
return (TestConstructorUtils.isAutowirableConstructor(executable, testClass, junitPropertyProvider) ||
ApplicationContext.class.isAssignableFrom(parameter.getType()) ||
supportsApplicationEvents(parameterContext) ||
ParameterResolutionDelegate.isAutowirable(parameter, parameterContext.getIndex()));
}
ParameterResolutionDelegate.isAutowirable
依靠注解来确定是否可以从 Spring 的 ApplicationContext
public static boolean isAutowirable(Parameter parameter, int parameterIndex) {
Assert.notNull(parameter, "Parameter must not be null");
AnnotatedElement annotatedParameter = getEffectiveAnnotatedParameter(parameter, parameterIndex);
return (AnnotatedElementUtils.hasAnnotation(annotatedParameter, Autowired.class) ||
AnnotatedElementUtils.hasAnnotation(annotatedParameter, Qualifier.class) ||
AnnotatedElementUtils.hasAnnotation(annotatedParameter, Value.class));
}
事实上,如果省略@Autowired注解,JUnit会抱怨缺少ParameterResolver:
org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [test.Mailer mailer] in constructor [public test.MailServiceTest(test.Mailer)].