Maven构建服务器未部署Consul时如何测试Consul DiscoveryClient功能
你遇到的报错是测试运行时没有可用的Consul服务导致连接失败,可以根据测试需求选择以下任意一种方案解决:
方案1:使用Testcontainers启动临时Consul实例(集成测试推荐)
该方案会在测试执行时自动拉起轻量Consul容器,测试结束后自动销毁,完全不依赖服务器预装Consul。
操作步骤:
- 首先在
pom.xml中添加Testcontainers相关依赖:
<dependency> <groupId>org.testcontainers</groupId> <artifactId>junit-jupiter</artifactId> <version>1.17.6</version> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>consul</artifactId> <version>1.17.6</version> <scope>test</scope> </dependency>
- 修改测试类,将Testcontainers启动的Consul地址绑定到Spring配置:
package com.example.demo2; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.consul.discovery.ConsulDiscoveryClient; import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; import org.testcontainers.consul.ConsulContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; @Testcontainers @SpringBootTest class Demo2ApplicationTests { @Container static final ConsulContainer consulContainer = new ConsulContainer("hashicorp/consul:1.14"); @DynamicPropertySource static void registerConsulProperties(DynamicPropertyRegistry registry) { registry.add("spring.cloud.consul.host", consulContainer::getHost); registry.add("spring.cloud.consul.port", consulContainer::getMappedPort); // 可在此处提前配置测试需要的服务注册、元数据等内容 } @Autowired private ConsulDiscoveryClient discoveryClient; @Test void contextLoads() { } @Test public void testClient() { List<ServiceInstance> instances = this.discoveryClient.getInstances("testConsulDiscovery"); assertThat(instances).as("instances was null").isNotNull(); assertThat(instances.isEmpty()).as("instances was empty").isFalse(); ServiceInstance instance = instances.get(0); assertThat(instance.isSecure()).as("instance was secure (https)").isFalse(); assertIpAddress(instance); assertThat(instance.getMetadata()).containsEntry("foo", "bar"); } }
- 只需保证Maven构建服务器安装了Docker环境即可,无需单独配置Consul。
方案2:Mock ConsulDiscoveryClient(单元测试推荐)
如果不需要测试和真实Consul的交互逻辑,只需要验证业务代码,可以直接Mock掉ConsulDiscoveryClient,不需要启动真实服务。
修改测试类如下:
package com.example.demo2; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.consul.discovery.ConsulDiscoveryClient; import java.util.List; import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; @SpringBootTest class Demo2ApplicationTests { @MockBean private ConsulDiscoveryClient discoveryClient; @Test void contextLoads() { } @Test public void testClient() { // 构造Mock返回数据 ServiceInstance mockInstance = new ServiceInstance() { @Override public String getServiceId() { return "testConsulDiscovery"; } @Override public String getHost() { return "127.0.0.1"; } @Override public int getPort() { return 8080; } @Override public boolean isSecure() { return false; } @Override public Map<String, String> getMetadata() { return Map.of("foo","bar"); } @Override public URI getUri() { return URI.create("http://127.0.0.1:8080"); } }; when(discoveryClient.getInstances("testConsulDiscovery")).thenReturn(List.of(mockInstance)); List<ServiceInstance> instances = this.discoveryClient.getInstances("testConsulDiscovery"); assertThat(instances).as("instances was null").isNotNull(); assertThat(instances.isEmpty()).as("instances was empty").isFalse(); ServiceInstance instance = instances.get(0); assertThat(instance.isSecure()).as("instance was secure (https)").isFalse(); assertIpAddress(instance); assertThat(instance.getMetadata()).containsEntry("foo", "bar"); } }
方案3:配置Maven Profile跳过Consul相关测试
如果暂时不需要在构建服务器运行这部分测试,可以配置Profile在无Consul环境自动跳过对应测试:
- 在
pom.xml中添加Profile配置:
<profiles> <profile> <id>no-consul</id> <activation> <activeByDefault>true</activeByDefault> </activation> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <excludedTestClasses> <exclude>com.example.demo2.Demo2ApplicationTests</exclude> </excludedTestClasses> </configuration> </plugin> </plugins> </build> </profile> </profiles>
本地运行测试时指定其他Profile即可执行完整测试,构建服务器默认会跳过Consul相关测试。
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

