Spring Boot 应用程序找不到用于 spock-spring 测试的占位符“spring.embedded.kafka.brokers”

tar*_*aro 5 spring spring-kafka

我正在尝试使用 Spring Boot、Spock-Spring 和嵌入式 Kafka 进行集成测试。我遵循了本指南,在那里我发现“由于嵌入式代理在随机端口上启动,我们可以\xe2\x80\x99t使用src/main/resources/application.yml属性文件中的修复值。幸运的是,将系统属性@ClassRule设置spring.embedded.kafka.brokers为嵌入式代理的地址(s)”。因此我有

\n\n
@ContextConfiguration\n@SpringBootTest(classes = [Application], webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)\n@DirtiesContext\n@Stepwise\n@ActiveProfiles("test")\nclass AnIntegrationTest extends Specification {\n\n  @Autowired\n  private KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry\n\n  @ClassRule\n  public static KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, true, "topic")\n\n  private KafkaTemplate<String, String> template\n\n  def setup() {\n    Map<String, Object> senderProperties = KafkaTestUtils.senderProps(embeddedKafka.getBrokersAsString())\n    ProducerFactory<String, String> producerFactory =\n            new DefaultKafkaProducerFactory<String, String>(senderProperties)\n    template = new KafkaTemplate<>(producerFactory)\n    template.setDefaultTopic("topic")\n    for (MessageListenerContainer messageListenerContainer : kafkaListenerEndpointRegistry\n            .getListenerContainers()) {\n        ContainerTestUtils.waitForAssignment(messageListenerContainer, embeddedKafka.getPartitionsPerTopic())\n    }\n  }\n\n  def "test"() {\n    given:\n      template.sendDefault("Hello")\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

application-test.yml我有

\n\n
kafka:\n  bootstrapservers: ${spring.embedded.kafka.brokers}\n
Run Code Online (Sandbox Code Playgroud)\n\n

在应用程序中,我使用 启动 Kafka 消费者spring-kafka。\n堆栈跟踪是

\n\n
java.lang.IllegalStateException: Failed to load ApplicationContext\n\n    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)\n    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)\n    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117)\n    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)\n    at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:44)\n    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230)\n    at org.spockframework.spring.SpringTestContextManager.prepareTestInstance(SpringTestContextManager.java:50)\n    at org.spockframework.spring.SpringInterceptor.interceptSetupMethod(SpringInterceptor.java:42)\n    at org.spockframework.runtime.extension.AbstractMethodInterceptor.intercept(AbstractMethodInterceptor.java:28)\n    at org.spockframework.runtime.extension.MethodInvocation.proceed(MethodInvocation.java:87)\n    at org.spockframework.runtime.extension.MethodInvocation.proceed(MethodInvocation.java:88)\n    at org.spockframework.runtime.extension.builtin.AbstractRuleInterceptor$1.evaluate(AbstractRuleInterceptor.java:37)\n    at org.togglz.junit.TogglzRule$1.evaluate(TogglzRule.java:127)\n    at org.spockframework.runtime.extension.builtin.TestRuleInterceptor.intercept(TestRuleInterceptor.java:38)\n    at org.spockframework.runtime.extension.MethodInvocation.proceed(MethodInvocation.java:87)\n    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)\n    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)\n    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)\n    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)\n    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)\nCaused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name \'kafkaListenerContainerFactoryConfiguration\': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder \'spring.embedded.kafka.brokers\' in value "${spring.embedded.kafka.brokers}"\n    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:372)\n    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264)\n    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)\n    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)\n    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)\n    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)\n    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)\n    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)\n    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)\n    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)\n    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)\n    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)\n    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)\n    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)\n    at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)\n    at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:120)\n    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)\n    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)\n    ... 19 more\nCaused by: java.lang.IllegalArgumentException: Could not resolve placeholder \'spring.embedded.kafka.brokers\' in value "${spring.embedded.kafka.brokers}"\n    at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)\n    at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)\n    at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:236)\n    at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:210)\n    at org.springframework.core.env.AbstractPropertyResolver.resolveNestedPlaceholders(AbstractPropertyResolver.java:227)\n    at org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:84)\n    at org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:61)\n    at org.springframework.core.env.AbstractEnvironment.getProperty(AbstractEnvironment.java:527)\n    at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$1.getProperty(PropertySourcesPlaceholderConfigurer.java:132)\n    at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$1.getProperty(PropertySourcesPlaceholderConfigurer.java:129)\n    at org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:81)\n    at org.springframework.core.env.PropertySourcesPropertyResolver.getPropertyAsRawString(PropertySourcesPropertyResolver.java:71)\n    at org.springframework.core.env.AbstractPropertyResolver$1.resolvePlaceholder(AbstractPropertyResolver.java:239)\n    at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:147)\n    at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)\n    at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:236)\n    at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:210)\n    at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$2.resolveStringValue(PropertySourcesPlaceholderConfigurer.java:172)\n    at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:831)\n    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1086)\n    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)\n    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)\n    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)\n    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366)\n    ... 36 more\n
Run Code Online (Sandbox Code Playgroud)\n\n

有人有线索吗?

\n

小智 7

确保在每个集成测试中都设置@SpringBootTest@EmbeddedKafka

当您使用注释同时运行多个集成测试时,这是常见的错误@SpringBootTest。由于您已经在应用程序配置器 bean 中注册,并且可能您也在某个地方使用DefaultKafkaConsumerFactory,因此您有义务在调用 spring-boot 应用程序的所有位置进行设置以在测试服务器容器上运行。负责调用注册kafka引擎所需的所有环境变量(其中包括)。DefaultKafkaProducerFactory@Value("${spring.kafka.bootstrap-servers}")@EmbeddedKafka(partitions = 1, topics = {"topic"})@EmbeddedKafkaEmbeddedKafkaContextCustomizerspring.embedded.kafka.brokers

如果没有@EmbeddedKafka在集成测试中,spring 在服务器上运行您的应用程序,但没有机制来设置 kafka 引擎使用的环境。


Gar*_*ell 2

我不熟悉 Spock,但一个简单的 Java JUnit 测试工作正常......

@SpringBootApplication
public class So47172973Application {

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

    @KafkaListener(topics = "foo")
    public void in(String in) {
        System.out.println(in);
    }

}
Run Code Online (Sandbox Code Playgroud)

spring:
  kafka:
    bootstrap-servers: 
    - ${spring.embedded.kafka.brokers}
    consumer:
      group-id: embedded1
      auto-offset-reset: earliest
Run Code Online (Sandbox Code Playgroud)

@RunWith(SpringRunner.class)
@SpringBootTest
public class So47172973ApplicationTests {

    @ClassRule
    public static KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, true, "foo");

    @Autowired
    private KafkaTemplate<String, String> template;

    @Test
    public void test() throws InterruptedException {
        template.send("foo", "bar");
        Thread.sleep(10_000);
    }

}
Run Code Online (Sandbox Code Playgroud)

有几点需要尝试:

使用注释代替...

@RunWith(SpringRunner.class)
@SpringBootTest
@EmbeddedKafka(controlledShutdown = true, topics = "foo")
public class So47172973ApplicationTests {

    @Autowired
    private KafkaTemplate<String, String> template;

    @Test
    public void test() throws InterruptedException {
        template.send("foo", "bar");
        Thread.sleep(10_000);
    }

}
Run Code Online (Sandbox Code Playgroud)

声明经纪人为@Bean...

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {So47172973ApplicationTests.Config.class, So47172973Application.class})
public class So47172973ApplicationTests {

    @Autowired
    private KafkaTemplate<String, String> template;

    @Test
    public void test() throws InterruptedException {
        template.send("foo", "bar");
        Thread.sleep(10_000);
    }

    @Configuration
    public static class Config {

        @Bean
        public KafkaEmbedded embeddedKafka() {
            return new KafkaEmbedded(1, true, "foo");
        }

    }

}
Run Code Online (Sandbox Code Playgroud)