识字粗堪供赋役,不须辛苦慕公卿。这篇文章主要讲述SpringCloud升级之路2020.0.x版-24.测试SPLoadBalancer相关的知识,希望能为你提供帮助。
文章图片
通过单元测试,我们也可以了解下一般我们实现 spring cloud 自定义的基础组件,怎么去单元测试。
这里的单元测试主要测试三个场景:
- 只返回同一个 zone 下的实例,其他 zone 的不会返回
- 对于多个请求,每个请求返回的与上次的实例不同。
- 对于多线程的每个请求,如果重试,返回的都是不同的实例
- 同步环境是 DiscoveryClient,异步环境是 ReactiveDiscoveryClient
- 同步环境负载均衡器是 LoadBalancer,异步环境负载均衡器是 ReactiveLoadBalancer
我们这里使用同步测试代码作为例子展示:
//SpringExtension也包含了MockitoJUnitRunner,所以 @Mock 等注解也生效了
@ExtendWith(SpringExtension.class)
@SpringBootTest(properties = {LoadBalancerEurekaAutoConfiguration.LOADBALANCER_ZONE + "=zone1"})
public class LoadBalancerTest {@EnableAutoConfiguration
@Configuration
public static class App {
@Bean
public DiscoveryClient myDiscoveryClient() {
ServiceInstance zone1Instance1 = Mockito.spy(ServiceInstance.class);
ServiceInstance zone1Instance2 = Mockito.spy(ServiceInstance.class);
ServiceInstance zone2Instance3 = Mockito.spy(ServiceInstance.class);
Map<
String, String>
zone1 = Map.ofEntries(
Map.entry("zone", "zone1")
);
Map<
String, String>
zone2 = Map.ofEntries(
Map.entry("zone", "zone2")
);
when(zone1Instance1.getMetadata()).thenReturn(zone1);
when(zone1Instance1.getInstanceId()).thenReturn("instance1");
when(zone1Instance2.getMetadata()).thenReturn(zone1);
when(zone1Instance2.getInstanceId()).thenReturn("instance2");
when(zone2Instance3.getMetadata()).thenReturn(zone2);
when(zone2Instance3.getInstanceId()).thenReturn("instance3");
DiscoveryClient spy = Mockito.spy(DiscoveryClient.class);
Mockito.when(spy.getInstances("testService"))
.thenReturn(List.of(zone1Instance1, zone1Instance2, zone2Instance3));
return spy;
}
}@SpyBean
private LoadBalancerClientFactory loadBalancerClientFactory;
@SpyBean
private Tracer tracer;
/**
* 只返回同一个 zone 下的实例
*/
@Test
public void testFilteredByZone() {
ReactiveLoadBalancer<
ServiceInstance>
testService =
loadBalancerClientFactory.getInstance("testService");
for (int i = 0;
i <
100;
i++) {
ServiceInstance server = Mono.from(testService.choose()).block().getServer();
//必须处于和当前实例同一个zone下
Assertions.assertEquals(server.getMetadata().get("zone"), "zone1");
}
}/**
* 返回不同的实例
*/
@Test
public void testReturnNext() {
ReactiveLoadBalancer<
ServiceInstance>
testService =
loadBalancerClientFactory.getInstance("testService");
Span span = tracer.nextSpan();
for (int i = 0;
i <
100;
i++) {
try (Tracer.SpanInScope cleared = tracer.withSpanInScope(span)) {
ServiceInstance server1 = Mono.from(testService.choose()).block().getServer();
ServiceInstance server2 = Mono.from(testService.choose()).block().getServer();
//每次选择的是不同实例
Assertions.assertNotEquals(server1.getInstanceId(), server2.getInstanceId());
}
}
}/**
* 跨线程,默认情况下是可能返回同一实例的,在我们的实现下,保持
* span 则会返回下一个实例,这样保证多线程环境同一个 request 重试会返回下一实例
*
* @throws Exception
*/
@Test
public void testSameSpanReturnNext() throws Exception {
Span span = tracer.nextSpan();
for (int i = 0;
i <
100;
i++) {
try (Tracer.SpanInScope cleared = tracer.withSpanInScope(span)) {
ReactiveLoadBalancer<
ServiceInstance>
testService =
loadBalancerClientFactory.getInstance("testService");
ServiceInstance server1 = Mono.from(testService.choose()).block().getServer();
AtomicReference<
ServiceInstance>
server2 = new AtomicReference<
>
();
Thread thread = new Thread(() ->
{
try (Tracer.SpanInScope cleared2 = tracer.withSpanInScope(span)) {
server2.set(Mono.from(testService.choose()).block().getServer());
}
});
thread.start();
thread.join();
System.out.println(i);
Assertions.assertNotEquals(server1.getInstanceId(), server2.get().getInstanceId());
}
}
}
}
运行测试,测试通过。
文章图片
我们这一节使用单元测试验证我们要实现的这些功能是否有效。下一节,我们将开始分析同步环境下的 Http 客户端,Open-Feign Client。
【SpringCloud升级之路2020.0.x版-24.测试SPLoadBalancer】
文章图片
推荐阅读
- Linux下大容量磁盘分区格式化
- DruidDeterminePartitionsJob源码解析
- 0003 - NameNode工作机制解析
- IDEA的5大调试技巧,你都会吗()
- 史上最简单的 Jmeter 跨线程组取参数值的两种办法 (不写代码)
- 你知道 JavaScript 中的 Arguments 对象都有哪些用途吗()
- Centos7.9安装教程
- Java程序员需要知道的操作系统知识汇总(持续更新)
- 面向多场景而设计的 Erda Pipeline