SpringCloud升级之路2020.0.x版-24.测试Spring Cloud LoadBalancer

本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford
通过单元测试,我们也可以了解下一般我们实现 spring cloud 自定义的基础组件,怎么去单元测试。
这里的单元测试主要测试三个场景:
- 只返回同一个 zone 下的实例,其他 zone 的不会返回
- 对于多个请求,每个请求返回的与上次的实例不同。
- 对于多线程的每个请求,如果重试,返回的都是不同的实例
同时,我们也需要针对同步和异步两个配置,分别进行测试,同步和异步两种配置测试逻辑是一样的,只是测试的 Bean 不一样:
- 同步环境是 DiscoveryClient,异步环境是 ReactiveDiscoveryClient
- 同步环境负载均衡器是 LoadBalancer,异步环境负载均衡器是 ReactiveLoadBalancer
同步测试代码请参考:LoadBalancerTest.java,异步测试代码请参考:LoadBalancerTest.java
我们这里使用同步测试代码作为例子展示:
//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。
微信搜索“我的编程喵”关注公众号,每日一刷,轻松提升技术,斩获各种offer:

SpringCloud升级之路2020.0.x版-24.测试Spring Cloud LoadBalancer的更多相关文章
- SpringCloud升级之路2020.0.x版-6.微服务特性相关的依赖说明
本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford spring-cl ...
- SpringCloud升级之路2020.0.x版-20. 启动一个 Eureka Server 集群
本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford 我们的业务集群结构 ...
- SpringCloud升级之路2020.0.x版-21.Spring Cloud LoadBalancer简介
本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford 我们使用 Spri ...
- SpringCloud升级之路2020.0.x版-23.订制Spring Cloud LoadBalancer
本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford 我们使用 Spri ...
- SpringCloud升级之路2020.0.x版-33. 实现重试、断路器以及线程隔离源码
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 在前面两节,我们梳理了实现 Feign 断路器以及线程隔离的思路,并说明了如何优化目前的负 ...
- SpringCloud升级之路2020.0.x版-40. spock 单元测试封装的 WebClient(上)
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 我们来测试下前面封装好的 WebClient,这里开始,我们使用 spock 编写 gro ...
- SpringCloud升级之路2020.0.x版-40. spock 单元测试封装的 WebClient(下)
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 我们继续上一节,继续使用 spock 测试我们自己封装的 WebClient 测试针对 r ...
- SpringCloud升级之路2020.0.x版-1.背景
本系列为之前系列的整理重启版,随着项目的发展以及项目中的使用,之前系列里面很多东西发生了变化,并且还有一些东西之前系列并没有提到,所以重启这个系列重新整理下,欢迎各位留言交流,谢谢!~ Spring ...
- SpringCloud升级之路2020.0.x版-41. SpringCloudGateway 基本流程讲解(1)
本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 接下来,将进入我们升级之路的又一大模块,即网关模块.网关模块我们废弃了已经进入维护状态的 ...
随机推荐
- 转载:使用jquery刷新当前页面以及其他js知识积累
转载:https://www.cnblogs.com/heguihui/p/10505949.html 如何使用jquery刷新当前页面 下面介绍全页面刷新方法:有时候可能会用到 window.loc ...
- 前端开发入门到进阶第三集【js和jquery的执行时间与页面加载的关系】
https://blog.csdn.net/u014179029/article/details/81603561 [原文链接]:https://www.cnblogs.com/eric-qin/p/ ...
- Appium - adb monkey参数(三)
monkey 参数 1.常规类参数 A.帮助类参数 monkey -h B.日志级别 $ adb shell monkey -v <event-count> . 2.事件类参数 A .执 ...
- uni-app&H5&Android混合开发三 || uni-app调用Android原生方法的三种方式
前言: 关于H5的调用Android原生方法的方式有很多,在该片文章中我主要简单介绍三种与Android原生方法交互的方式. 一.H5+方法调用android原生方法 H5+ Android开发规范官 ...
- 【贪心+排序】凌乱的yyy / 线段覆盖 luogu-1803
题目描述 现在各大oj上有n个比赛,每个比赛的开始.结束的时间点是知道的. yyy认为,参加越多的比赛,noip就能考的越好(假的) 所以,他想知道他最多能参加几个比赛. 由于yyy是蒟蒻,如果要参加 ...
- salesforce Integration 概览(一) 杂篇
本篇参考:https://resources.docs.salesforce.com/sfdc/pdf/integration_patterns_and_practices.pdf 我们在做sales ...
- js 数据存入数组
var tag = []; $('.deltag').each(function(){ if($(this).attr("checked")== 'checked'){ tag.p ...
- IIS短文件名漏洞原理与挖掘思路
首先来几个网址先了解一下 https://www.jb51.net/article/166405.htm https://www.freebuf.com/articles/web/172561.htm ...
- 字节跳动、快手等大厂Android面试刨根问底之内存泄露篇
现在快手字节跳动等公司都在大量招人,薪资优厚,但是想进去却没那么简单,面过的人都知道,这些公司的面试官巴不得把你会的东西都给你挖出来,所以要深入复习知识点,让自己耐问一点.一下是针对内存泄露真实面试过 ...
- git基本命令-直接上手使用
git基本命令-直接上手使用 此篇为直接是使用git,如果想了解其原理和其他详细信息,请关注我,看其它相关文章 git创建仓库(初始化仓库) 使用当前目录作为仓库 git init // 执行该目录后 ...