Spring boot EmbeddedKafka AdminClient在Spring应用程序启动测试之前关闭

Spring boot EmbeddedKafka AdminClient在Spring应用程序启动测试之前关闭,spring-boot,spring-test,spring-kafka,spring-boot-test,Spring Boot,Spring Test,Spring Kafka,Spring Boot Test,我正在尝试为SpringKafka应用程序编写集成测试(SpringBoot2.0.6,SpringKafka 2.1.10)我看到了很多INFO org.apache.zookeeper.server.prerequestprocessor的实例-在处理sessionid:0x166e432ebec0001类型:create cxid:0x5e zxid:0x24 txntype:-1请求路径:n/a错误路径:/brokers/topics/my topic/partitions错误:keep

我正在尝试为SpringKafka应用程序编写集成测试(SpringBoot2.0.6,SpringKafka 2.1.10)我看到了很多
INFO org.apache.zookeeper.server.prerequestprocessor的实例-在处理sessionid:0x166e432ebec0001类型:create cxid:0x5e zxid:0x24 txntype:-1请求路径:n/a错误路径:/brokers/topics/my topic/partitions错误:keeperrorcode=NoNode for/代理/主题/我的主题/分区
,以及Spring应用程序启动前日志中显示的各种类型的路径(
/brokers
/brokers/topics
,等等)。AdminClient随后关闭,并记录此消息:

DEBUG org.apache.kafka.common.network.Selector - [SocketServer brokerId=0] Connection with /127.0.0.1 disconnected
java.io.EOFException: null
at org.apache.kafka.common.network.NetworkReceive.readFromReadableChannel(NetworkReceive.java:124)
at org.apache.kafka.common.network.NetworkReceive.readFrom(NetworkReceive.java:93)
at org.apache.kafka.common.network.KafkaChannel.receive(KafkaChannel.java:235)
at org.apache.kafka.common.network.KafkaChannel.read(KafkaChannel.java:196)
at org.apache.kafka.common.network.Selector.attemptRead(Selector.java:547)
at org.apache.kafka.common.network.Selector.pollSelectionKeys(Selector.java:483)
at org.apache.kafka.common.network.Selector.poll(Selector.java:412)
at kafka.network.Processor.poll(SocketServer.scala:575)
at kafka.network.Processor.run(SocketServer.scala:492)
at java.lang.Thread.run(Thread.java:748)
我在测试中使用@ClassRule启动选项,如下所示:

@ClassRule
@Shared
private KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, true, 'my-topic')
,自动连接卡夫卡模板,并根据嵌入的卡夫卡值设置连接的弹簧属性:

def setupSpec() {
    System.setProperty('spring.kafka.bootstrap-servers', embeddedKafka.getBrokersAsString());
    System.setProperty('spring.cloud.stream.kafka.binder.zkNodes', embeddedKafka.getZookeeperConnectionString());
}
一旦Spring应用程序启动,我可以再次看到用户级KeeperException消息的实例:
o.a.z.server.PrerequestProcessor:Get user level KeeperException when processing sessionid:0x166e445836d0001 type:setData cxid:0x6b zxid:0x2b txntype:-1请求路径:n/a错误路径:/config/topics/\u consumer\u偏移错误:KeeperErrorCode=Noode for/配置/topics/\u消费者\u偏移量


知道我哪里出了问题吗?我可以提供其他设置信息和日志消息,但只是对最初可能最有用的内容进行了有根据的猜测。

我不熟悉Spock,但我知道
@KafkaListener
方法是在其自己的线程上调用的,因此您不能直接在
然后:
块中断言它

您需要在测试用例中以某种方式确保阻塞等待

我尝试使用
BlockingVariable
来对抗真正的服务notmock,我在日志中看到了您的
println(message)
。但是
BlockingVariable
在某种程度上对我来说仍然不起作用:

@DirtiesContext
@SpringBootTest(classes = [KafkaIntTestApplication.class])
@ActiveProfiles('test')
class CustomListenerSpec  extends Specification {

    @ClassRule
    @Shared
    public KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, false, 'my-topic')

    @Autowired
    private KafkaTemplate<String, String> template

    @SpyBean
    private SimpleService service

    final def TOPIC_NAME = 'my-topic'

    def setupSpec() {
        System.setProperty('spring.kafka.bootstrapServers', embeddedKafka.getBrokersAsString());
    }

    def 'Sample test'() {
        given:
        def testMessagePayload = "Test message"
        def message = MessageBuilder.withPayload(testMessagePayload).setHeader(KafkaHeaders.TOPIC, TOPIC_NAME).build()
        def result = new BlockingVariable<Boolean>(5)
        service.handleMessage(_) >> {
            result.set(true)
        }

        when: 'We put a message on the topic'
        template.send(message)

        then: 'the service should be called'
        result.get()
    }
}
我还必须添加此依赖项:

testImplementation "org.hamcrest:hamcrest-core"
更新


嗯。真正的问题是,
MockConfig
对于测试上下文配置不可见,而
@Import(MockConfig.class)
起到了作用。其中,
@Primary
还为我们提供了额外的信号,告诉我们在测试类中选择什么bean进行注入。

@ArtemBilan的回答让我走上了正确的道路,因此感谢他插话,在查看其他
BlockingVariable
文章和示例后,我能够找到答案。我在模拟的响应中使用了
BlockingVariable
,而不是作为回调。调用mock的响应时,使其将值设置为true,然后
块执行
result.get()
并通过测试

@DirtiesContext
@ActiveProfiles('test')
@SpringBootTest
@Import(MockConfig.class)
class CustomListenerSpec extends TestSpecBase {

    @ClassRule
    @Shared
    private KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, false, TOPIC_NAME)

    @Autowired
    private KafkaTemplate<String, String> template

    @Autowired
    private SimpleService service

    final def TOPIC_NAME = 'my-topic'

    def setupSpec() {
        System.setProperty('spring.kafka.bootstrap-servers', embeddedKafka.getBrokersAsString());
    }

    def 'Sample test'() {
        def testMessagePayload = "Test message"
        def message = MessageBuilder.withPayload(testMessagePayload).setHeader(KafkaHeaders.TOPIC, TOPIC_NAME).build()
        def result = new BlockingVariable<Boolean>(5)
        service.handleMessage(_ as String) >> {
            result.set(true)
        }

        when: 'We put a message on the topic'
        template.send(message)

        then: 'the service should be called'
        result.get()
    }
}
@DirtiesContext
@ActiveProfiles(“测试”)
@春靴测试
@导入(MockConfig.class)
类CustomListenerSpec扩展了TestSpecBase{
@阶级规则
@共享
private KafkameBedded embeddedKafka=新KafkameBedded(1,false,主题名称)
@自动连线
私有KafkaTemplate模板
@自动连线
私有SimpleService服务
final def TOPIC_NAME='我的主题'
def setupSpec(){
System.setProperty('spring.kafka.bootstrap servers',embeddedKafka.getBrokersAsString());
}
def“样本测试”(){
def testMessagePayload=“测试消息”
def message=MessageBuilder.withPayload(testMessagePayload).setHeader(KafkaHeaders.TOPIC,TOPIC_NAME).build()
def结果=新阻塞变量(5)
service.handleMessage(u作为字符串)>>{
result.set(真)
}
当:'我们在主题上留言'
模板发送(消息)
然后:“应该调用服务”
result.get()
}
}

也许您可以与我们分享一个简单的GitHub项目,以便播放和复制?Thanks@ArtemBilan下面是一个示例项目,感谢您查看:
@DirtiesContext
@ActiveProfiles('test')
@SpringBootTest
@Import(MockConfig.class)
class CustomListenerSpec extends TestSpecBase {

    @ClassRule
    @Shared
    private KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, false, TOPIC_NAME)

    @Autowired
    private KafkaTemplate<String, String> template

    @Autowired
    private SimpleService service

    final def TOPIC_NAME = 'my-topic'

    def setupSpec() {
        System.setProperty('spring.kafka.bootstrap-servers', embeddedKafka.getBrokersAsString());
    }

    def 'Sample test'() {
        def testMessagePayload = "Test message"
        def message = MessageBuilder.withPayload(testMessagePayload).setHeader(KafkaHeaders.TOPIC, TOPIC_NAME).build()
        def result = new BlockingVariable<Boolean>(5)
        service.handleMessage(_ as String) >> {
            result.set(true)
        }

        when: 'We put a message on the topic'
        template.send(message)

        then: 'the service should be called'
        result.get()
    }
}