使用@SpyBean 时找不到定义 [SpyDefinition... 的 bean

No bean found for definition [SpyDefinition... when using @SpyBean

我有一个使用 @Component 内部的 @KafkaListener 侦听 Kafka 消息的应用程序。现在我想用 Kafka 测试容器(在后台启动 Kafka)进行集成测试。在我的测试中,我想验证侦听器方法是否已调用并完成,但是当我在测试中使用 @SpyBean 时,我得到:

No bean found for definition [SpyDefinition@7a939c9e name = '', typeToSpy = com.demo.kafka.MessageListener, reset = AFTER]

我正在使用 Kotling,重要 classes:

Class 测试

@Component
class MessageListener(private val someRepository: SomeRepository){

    @KafkaListener
    fun listen(records: List<ConsumerRecord<String, String>>) {
         // do something with someRepository
    }
}

基础测试class

@ExtendWith(SpringExtension::class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class KafkaContainerTests {

    // some functionality to spin up kafka testcontainer

}

测试class

class MessageListenerTest @Autowired constructor(
        private val someRepository: SomeRepository
) : KafkaContainerTests() {


    @SpyBean
    private lateinit var messageListenerSpy: MessageListener

    private var messageListenerLatch = CountDownLatch(1)

    @BeforeAll
    fun setupLatch() {
        logger.debug("setting up latch")

        doAnswer {
            it.callRealMethod()
            messageListenerLatch.count
        }.whenever(messageListenerSpy).listen(any())
    }

    @Test
    fun testListener(){
        sendKafkaMessage(someValidKafkaMessage)

        // assert that the listen method is being called & finished
        assertTrue(messageListenerLatch.await(20, TimeUnit.SECONDS))
        // and assert someRepository is called
    }
}

我感到困惑的原因是,当我将 MessageListener 添加到 MessageListenerTest@Autowired 构造函数时,它确实成功注入了。

为什么使用@SpyBean时测试找不到bean?

我用 Java 效果很好:

@SpringBootTest
class So58184716ApplicationTests {

    @SpyBean
    private Listener listener;

    @Test
    void test(@Autowired KafkaTemplate<String, String> template) throws InterruptedException {
        template.send("so58184716", "foo");
        CountDownLatch latch = new CountDownLatch(1);
        willAnswer(inv -> {
            inv.callRealMethod();
            latch.countDown();
            return null;
        }).given(this.listener).listen("foo");
        assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue();
        verify(this.listener).listen("foo");
    }

}

@SpringBootApplication
public class So58184716Application {

    public static void main(String[] args) {
        SpringApplication.run(So58184716Application.class, args);
    }


    @Bean
    public NewTopic topic() {
        return TopicBuilder.name("so58184716").partitions(1).replicas(1).build();
    }
}

@Component
class Listener {

    @KafkaListener(id = "so58184716", topics = "so58184716")
    public void listen(String in) {
        System.out.println(in);
    }

}