You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Quarkus集成测试未加载测试属性,误用环境变量排查

问题

我有一个消费Kafka主题的Quarkus应用,用TestContainers编写了Kafka消费者集成测试。但运行测试时发现,明明已经定义了测试属性,系统还是会读取.zshrc文件里KAFKA_BOOTSTRAP_SERVERS环境变量指向的真实Broker地址,而非测试配置的地址。删掉.zshrc里的这个环境变量后测试就能正常运行,但保留的话就会尝试连接开发环境服务器,请问哪里遗漏了?

应用配置

kafka:
  bootstrap:
    servers: ${KAFKA_BOOTSTRAP_SERVERS:localhost:9092}

  security:
    protocol: SASL_SSL
  sasl:
    mechanism: SCRAM-SHA-512
  jaas:
    config: org.apache.kafka.common.security.scram.ScramLoginModule required username="${KAFKA_CONSUMER_USERNAME}"
    password="${KAFKA_CONSUMER_PASSWORD}";


"%test":
   kafka:
     bootstrap:
       servers: kafka:9092
     security:
       protocol: PLAINTEXT
     sasl:
       mechanism: PLAIN

KafkaResource类

public class KafkaResource implements QuarkusTestResourceLifecycleManager {


    private static KafkaContainer kafkaContainer;

    private static String bootstrapServers;

    @Override
    public Map<String, String> start() {
   
        kafkaContainer = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:latest"))
                .withKraft();
        kafkaContainer.start();
        bootstrapServers = kafkaContainer.getBootstrapServers();
        return Map.of("kafka.bootstrap.servers", 
        kafkaContainer.getBootstrapServers());
   
        return Collections.emptyMap();
    }

    @Override
    public void stop() {
        kafkaContainer.stop();
    }

    public static String getBootstrapServers() {
       return bootstrapServers;
    }
}

消费者测试代码

@QuarkusTest
@QuarkusTestResource(KafkaResource.class)
class ConsumerTest {

  @InjectSpy
  EventConsumer eventConsumer;

  @Test
  void testConsumer() throws InvalidProtocolBufferException, InterruptedException {
    String eventId = "sport1234";
    Event event = Event.newBuilder().setEventId(eventId)
            .build();
    produceTestMessage(event);

    Mockito.verify(eventConsumer, timeout(5000)).consumeState(event.toByteArray());
    System.out.println("Number of invocations: " + Mockito.mockingDetails(eventConsumer).getInvocations().size());
  }

  private void produceTestMessage(Event event) {
    // Create a Kafka producer configuration
    String kafkaBootstrapServers = KafkaResource.getBootstrapServers();
    Properties producerProps = new Properties();
    producerProps.put("bootstrap.servers", kafkaBootstrapServers);
    producerProps.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
    producerProps.put("value.serializer", "com.org.events.EventProtoKafkaSerializer");

    try (Producer<String, Event> producer = new KafkaProducer<>(producerProps)) {
        ProducerRecord<String, Event> record = new ProducerRecord<>("test_topic", event.getEventId(), event);
        producer.send(record).get(); // Wait for the message to be sent
    } catch (Exception e) {
        throw new RuntimeException("Error producing test message", e);
    }
 }
}

依赖配置

implementation 'io.quarkus:quarkus-smallrye-reactive-messaging-kafka'
testImplementation 'io.quarkus:quarkus-junit5'
testImplementation 'io.quarkus:quarkus-junit5-mockito'
testImplementation 'io.rest-assured:rest-assured'
testImplementation 'io.quarkus:quarkus-jacoco'
testImplementation 'org.assertj:assertj-core:3.24.2'
testImplementation 'org.testcontainers:junit-jupiter:1.19.3'
testImplementation 'org.testcontainers:mysql:1.19.3'
testImplementation 'org.testcontainers:kafka:1.19.3'

解决方案

问题核心是系统环境变量的优先级高于Quarkus测试配置,再加上测试配置的写法和TestResource的属性覆盖逻辑没处理到位,导致环境变量直接覆盖了测试配置。

具体原因

  1. Quarkus属性优先级规则:系统环境变量 > 配置文件中的测试环境配置。本地KAFKA_BOOTSTRAP_SERVERS环境变量存在时,会直接跳过application.yaml里%test块的配置。
  2. 你在%test块中写的kafka.bootstrap.servers: kafka:9092无法生效,因为环境变量的优先级更高;同时TestResource返回的属性默认优先级也低于环境变量。

解决步骤

1. 修改KafkaResource,强制覆盖环境变量

在TestResource启动时,直接设置系统属性(优先级高于环境变量)并清除对应的环境变量,确保测试用TestContainer的地址:

@Override
public Map<String, String> start() {
    kafkaContainer = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:latest"))
            .withKraft();
    kafkaContainer.start();
    bootstrapServers = kafkaContainer.getBootstrapServers();
    
    // 设置系统属性,优先级高于环境变量
    System.setProperty("kafka.bootstrap.servers", bootstrapServers);
    // 清除环境变量避免干扰
    System.getenv().remove("KAFKA_BOOTSTRAP_SERVERS");
    
    return Map.of("kafka.bootstrap.servers", bootstrapServers);
}

2. 调整application.yaml的测试配置写法

修改测试环境的配置,让它优先使用TestResource注入的属性,而非读取系统环境变量:

"%test":
   kafka:
     bootstrap:
       servers: "${kafka.bootstrap.servers:kafka:9092}"
     security:
       protocol: PLAINTEXT
     sasl:
       mechanism: PLAIN

3. 可选:用@TestPropertySource强制锁死配置

在测试类上添加注解,进一步确保测试时使用指定属性:

@QuarkusTest
@QuarkusTestResource(KafkaResource.class)
@TestPropertySource(properties = {"kafka.bootstrap.servers=${kafka.bootstrap.servers}"})
class ConsumerTest {
    // ... 测试代码
}

验证方法

可以在测试中注入配置属性,打印实际使用的地址确认是否生效:

@Inject
@ConfigProperty(name = "kafka.bootstrap.servers")
String actualBootstrapServers;

@Test
void verifyBootstrapAddress() {
    System.out.println("实际使用的Kafka地址: " + actualBootstrapServers);
    // 正常应该输出TestContainer的地址,比如localhost:xxxx
}

内容的提问来源于stack exchange,提问作者APK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 12:50:21