【问题标题】:Why does @SpringBootTest need @Autowired in constructor injection为什么@SpringBootTest 在构造函数注入中需要@Autowired
【发布时间】:2021-03-17 11:08:01
【问题描述】:

一个更普遍的问题。如果在常规 Spring 托管类中使用构造函数注入,则类会自动装配,而不需要 @Autowired 注释,即。 e.:

@Service
class MailService(
  private val projectService: ProjectService,
  private val mailer: Mailer
) { ... }

在@SpringBootTest 类中遵循相同的构造函数注入原则,您需要将@Autowired 注解设置为构造函数参数,否则将无法注入类,即。 e.:

@SpringBootTest
internal class MailerTest(
  @Autowired private val mailer: Mailer
) { ... }

为什么会出现这种差异?

【问题讨论】:

    标签: spring kotlin testing junit mockito


    【解决方案1】:

    对于 SpringBoot 应用程序,是 spring 负责连接 bean。

    在 JUnit 5 的情况下,Spring 管理的 Bean 必须注入到 JUnit 管理的测试类的实例中。幸运的是,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)].
    

    【讨论】:

    • 这是最好的答案,非常感谢您抽出宝贵的时间!
    猜你喜欢
    • 2021-08-29
    • 2018-06-02
    • 2020-03-10
    • 1970-01-01
    • 2021-06-17
    • 2021-08-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多