【问题标题】:Why Spring @Qualifier does not work with Spock and Spring Boot为什么 Spring @Qualifier 不适用于 Spock 和 Spring Boot
【发布时间】:2015-07-07 11:01:18
【问题描述】:

我正在尝试为 Spock 中的控制器编写测试。

@ContextConfiguration(loader = SpringApplicationContextLoader.class,
    classes = [Application.class, CreateUserControllerTest.class])
@WebAppConfiguration
@Configuration
class CreateUserControllerTest extends Specification {

    @Autowired
    @Qualifier("ble")
    PasswordEncryptor passwordEncryptor

    @Autowired
    UserRepository userRepository

    @Autowired
    WebApplicationContext context

    @Autowired
    CreateUserController testedInstance

    def "Injection works"() {
        expect:
        testedInstance instanceof CreateUserController
        userRepository != null
    }

    @Bean
    public UserRepository userRepository() {
        return Mock(UserRepository.class)
    }

    @Bean(name = "ble")
    PasswordEncryptor passwordEncryptor() {
        return Mock(PasswordEncryptor)
    }

}

Application 类只是 Spring Boot 最简单的配置(启用自动扫描)。它提供了一个带 PasswordEncryptor。我想用提供模拟的 bean 替换 Application 中的这个 bean。

但不幸的是 Spring 抛出了 NoUniqueBeanDefinitionException:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.jasypt.util.password.PasswordEncryptor] is defined: expected single matching bean but found 2: provide,ble
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1054)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:942)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:533)
... 54 more

@Qualifier 注释似乎根本不起作用。我能做什么?

编辑

问题不在于CreateUserControllerTest,而在于CreateUserController。

public class CreateUserController {
    @Autowired
    private PasswordEncryptor encryptor;
}

没有@Qualifier注解,所以Spring不知道应该注入哪个bean。不幸的是,我不知道如何让 Spring 用本地配置替换 Application 中的 PasswordEncryptor bean。

【问题讨论】:

  • 我强烈建议改用构造函数注入。这使您可以轻松控制注入到被测类中的内容。

标签: java spring testing spring-boot spock


【解决方案1】:

@Qualifier 是连接一个特定的 bean 实例,如果你有同一个接口的多个实现的话。

但您仍然需要在 spring 上下文中为每个 bean 设置一个“唯一”名称。

因此,您尝试注册两个名称为“passwordEncryptor”的 bean。一个在您的测试中,另一个似乎在您的实际代码“Application.class”中。

如果您想模拟“PasswordEncryptor”,请使用@Mock 或@Spy。 (或)如果要避免错误,则更改方法名称以避免实例名称冲突。

@Mock
private PasswordEncryptor passwordEncryptor;

or

@Spy
private PasswordEncryptor passwordEncryptor;

编辑

该错误的另一种可能性是您在代码中的某处为“passwordEncryptor”定义了一个@Autowired,而没有@Qualifier 标签,

但是

您定义了两个 @Bean(name="...") passwordEncryptor 实例,因此 Spring 上下文在选择哪一个来“自动连接”该字段时感到困惑。

【讨论】:

  • 除非我遗漏了什么 expected single matching bean but found 2: provide,ble 暗示 bean 有不同的名称。
  • 谢谢 morfic。编辑了答案。
  • 谢谢你们。现在我发现测试中的自动装配字段不是问题,而是测试实例中存在问题。 CreateUserController 内部有 @Autowired 注释到 passwordEncryptor 但没有限定符,因此存在冲突。不幸的是我不能使用@Mock注解,因为我想使用Spock的模拟框架(它不提供模拟注入)。
猜你喜欢
  • 2017-05-15
  • 1970-01-01
  • 1970-01-01
  • 2018-08-06
  • 2016-11-27
  • 2018-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多