《高性能Redis组件》测试验证-第01节:高性能Redis组件单元测试场景验证
作者:冰河
星球:http://m6z.cn/6aeFbs
博客:https://binghe.site
文章汇总:https://binghe.site/md/all/all.html
源码获取地址:https://t.zsxq.com/0dhvFs5oR
沉淀,成长,突破,帮助他人,成就自我。
- 本章难度:★★☆☆☆
- 本章重点:对高性能Redis组件实现的脱敏功能进行单元测试,从总体上理解高性能Redis组件防缓存击穿、穿透和雪崩问题的核心设计思想,并从全局视角了解高性能Redis组件的设计和架构思想,并能够将其灵活应用到自身实际项目中。
大家好,我是冰河~~
有一定工作经验的小伙伴都知道,在实际工作中,我们自己开发的功能在提测前,都是需要我们自己编写单元测试,并且需要所有单元测试都通过后才能提交测试的。高性能Redis组件亦是如此,我们开发完高性能Redis组件的核心功能后,也需要对功能进行单元测试。
一、前言
截止到目前,我们完成了高性能Redis组件的核心功能,包括:基础功能的设计与实现、分布锁的设计与实现、防缓存击穿、穿透和雪崩的核心设计与实现。这些落地实现的代码功能是否符合我们的预期,就需要针对落地实现的方法进行单元测试。所以,接下来,我们要对高性能Redis组件对外提供的接口方法进行单元测试。
二、本节诉求
对高性能Redis组件实现的脱敏功能进行单元测试,从总体上理解高性能Redis组件防缓存击穿、穿透和雪崩问题的核心设计思想,并从全局视角了解高性能Redis组件的设计和架构思想,并能够将其灵活应用到自身实际项目中。
三、单元测试验证
本节,会对高性能Redis组件接口对外提供的方法进行单元测试。
3.1 创建测试模型
为了更好的进行单元测试,在正式进行单元测试之前,创建单元测试的对象模型User类。User类的代码也比较简单,就是一个包含id和name的实体类。
源码详见:io.binghe.redis.plugin.test.bean.User。
public class User {
private Long id;
private String name;
public User() {
}
public User(Long id, String name) {
this.id = id;
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return JSONUtil.toJsonStr(this);
}
}
3.2 编写单元测试
创建DistributeCacheServiceTest类编写单元测试方法。
DistributeCacheServiceTest类的源码详见:io.binghe.redis.plugin.test.DistributeCacheServiceTest。
@SpringBootTest
@RunWith(SpringRunner.class)
public class DistributeCacheServiceTest {
@Autowired
private DistributeCacheService distributeCacheService;
@Test
public void testQueryWithPassThrough(){
User user = distributeCacheService.queryWithPassThrough("pass:through:", 1002852L, User.class, this::getUser, 60L, TimeUnit.SECONDS);
System.out.println(JSONUtil.toJsonStr(user));
}
@Test
public void testQueryWithPassThroughWithoutArgs(){
User user = distributeCacheService.queryWithPassThroughWithoutArgs("pass:through001:", User.class, this::getUserWithoutArgs, 60L, TimeUnit.SECONDS);
System.out.println(JSONUtil.toJsonStr(user));
}
@Test
public void testQuerySimpleDataWithPassThrough(){
Integer id = distributeCacheService.queryWithPassThrough("pass:through2:", 100285210, Integer.class, this::getId, 60L, TimeUnit.SECONDS);
System.out.println(id);
}
@Test
public void testQuerySimpleDataWithPassThroughWithoutArgs(){
Integer id = distributeCacheService.queryWithPassThroughWithoutArgs("pass:through2002:", Integer.class, this::getIdWithoutArgs, 60L, TimeUnit.SECONDS);
System.out.println(id);
}
@Test
public void testQueryWithPassThroughList(){
List<User> list = distributeCacheService.queryWithPassThroughList("pass:through:list:", null, User.class, this::getUserList, 60L, TimeUnit.SECONDS);
System.out.println(JSONUtil.toJsonStr(list));
}
@Test
public void testQueryWithPassThroughListWithoutArgs(){
List<User> list = distributeCacheService.queryWithPassThroughListWithoutArgs("pass:through:list003:", User.class, this::getUserListWithoutArgs, 60L, TimeUnit.SECONDS);
System.out.println(JSONUtil.toJsonStr(list));
}
@Test
public void testQuerySimpleDataWithPassThroughList(){
List<Integer> list = distributeCacheService.queryWithPassThroughList("pass:through:list2:", 100285211, Integer.class, this::getIds, 60L, TimeUnit.SECONDS);
System.out.println(JSONUtil.toJsonStr(list));
}
@Test
public void testQuerySimpleDataWithPassThroughListWithoutArgs(){
List<Integer> list = distributeCacheService.queryWithPassThroughListWithoutArgs("pass:through:list2004:", Integer.class, this::getIdsWithoutArgs, 60L, TimeUnit.SECONDS);
System.out.println(JSONUtil.toJsonStr(list));
}
@Test
public void testQueryWithLogicalExpire(){
User user = distributeCacheService.queryWithLogicalExpire("logical:expire:", 1002852L, User.class, this::getUser, 60L, TimeUnit.SECONDS);
System.out.println(JSONUtil.toJsonStr(user));
}
@Test
public void testQueryWithLogicalExpireWithoutArgs(){
User user = distributeCacheService.queryWithLogicalExpireWithoutArgs("logical:expire005:", User.class, this::getUserWithoutArgs, 60L, TimeUnit.SECONDS);
System.out.println(JSONUtil.toJsonStr(user));
}
@Test
public void testQuerySimpleDataWithLogicalExpire(){
Integer id = distributeCacheService.queryWithLogicalExpire("logical:expire2:", 100285212, Integer.class, this::getId, 60L, TimeUnit.SECONDS);
System.out.println(id);
}
@Test
public void testQuerySimpleDataWithLogicalExpireWithoutArgs(){
Integer id = distributeCacheService.queryWithLogicalExpireWithoutArgs("logical:expire2006:", Integer.class, this::getIdWithoutArgs, 60L, TimeUnit.SECONDS);
System.out.println(id);
}
@Test
public void testQueryWithLogicalExpireList(){
List<User> list = distributeCacheService.queryWithLogicalExpireList("logical:expire:list:", null, User.class, this::getUserList, 60L, TimeUnit.SECONDS);
System.out.println(JSONUtil.toJsonStr(list));
}
@Test
public void testQueryWithLogicalExpireListWithoutArgs(){
List<User> list = distributeCacheService.queryWithLogicalExpireListWithoutArgs("logical:expire:list007:", User.class, this::getUserListWithoutArgs, 60L, TimeUnit.SECONDS);
System.out.println(JSONUtil.toJsonStr(list));
}
@Test
public void testQuerySimpleDataWithLogicalExpireList(){
List<Integer> list = distributeCacheService.queryWithLogicalExpireList("logical:expire:list2:", 100285213, Integer.class, this::getIds, 60L, TimeUnit.SECONDS);
System.out.println(JSONUtil.toJsonStr(list));
}
@Test
public void testQuerySimpleDataWithLogicalExpireListWithoutArgs(){
List<Integer> list = distributeCacheService.queryWithLogicalExpireListWithoutArgs("logical:expire:list2008:", Integer.class, this::getIdsWithoutArgs, 60L, TimeUnit.SECONDS);
System.out.println(JSONUtil.toJsonStr(list));
}
@Test
public void testQueryWithMutex(){
User user = distributeCacheService.queryWithMutex("mutex:", 1002852L, User.class, this::getUser, 60L, TimeUnit.SECONDS);
System.out.println(JSONUtil.toJsonStr(user));
}
@Test
public void testQueryWithMutexWithoutArgs(){
User user = distributeCacheService.queryWithMutexWithoutArgs("mutex009:", User.class, this::getUserWithoutArgs, 60L, TimeUnit.SECONDS);
System.out.println(JSONUtil.toJsonStr(user));
}
@Test
public void testQuerySimpleDataWithMutex(){
Integer id = distributeCacheService.queryWithMutex("mutex2:", 100285214, Integer.class, this::getId, 60L, TimeUnit.SECONDS);
System.out.println(id);
}
@Test
public void testQuerySimpleDataWithMutexWithoutArgs(){
Integer id = distributeCacheService.queryWithMutexWithoutArgs("mutex2010:", Integer.class, this::getIdWithoutArgs, 60L, TimeUnit.SECONDS);
System.out.println(id);
}
@Test
public void testQueryWithMutexList(){
List<User> list = distributeCacheService.queryWithMutexList("mutex:list:", null, User.class, this::getUserList, 60L, TimeUnit.SECONDS);
System.out.println(JSONUtil.toJsonStr(list));
}
@Test
public void testQueryWithMutexListWithoutArgs(){
List<User> list = distributeCacheService.queryWithMutexListWithoutArgs("mutex:list011:", User.class, this::getUserListWithoutArgs, 60L, TimeUnit.SECONDS);
System.out.println(JSONUtil.toJsonStr(list));
}
@Test
public void testQuerySimpleDataWithMutexList(){
List<Integer> list = distributeCacheService.queryWithMutexList("mutex:list2:", 123, Integer.class, this::getIds, 60L, TimeUnit.SECONDS);
System.out.println(JSONUtil.toJsonStr(list));
}
@Test
public void testQuerySimpleDataWithMutexListWithoutArgs(){
List<Integer> list = distributeCacheService.queryWithMutexListWithoutArgs("mutex:list2012:", Integer.class, this::getIdsWithoutArgs, 60L, TimeUnit.SECONDS);
System.out.println(JSONUtil.toJsonStr(list));
}
/**
* 模拟带参数从数据库查询对象
*/
public User getUser(Long id){
return new User(id, "binghe");
}
/**
* 默认不带参数从数据库查询对象
*/
public User getUserWithoutArgs(){
return new User(1L, "binghe");
}
/**
* 模拟带参数查询从数据库对象列表
*/
public List<User> getUserList(String type){
return Arrays.asList(
new User(1L, "binghe001"),
new User(2L, "binghe002"),
new User(3L, "binghe003")
);
}
/**
* 模拟不带参数从数据库查询对象列表
*/
public List<User> getUserListWithoutArgs(){
return Arrays.asList(
new User(1L, "binghe001"),
new User(2L, "binghe002"),
new User(3L, "binghe003")
);
}
/**
* 模拟带参数从数据库查询简单数据类型数据
*/
public Integer getId(Integer id){
return id;
}
/**
* 模拟不带参数从数据库查询简单数据类型数据
*/
public Integer getIdWithoutArgs(){
return 0;
}
/**
* 模拟带参数从数据库查询简单数据类型数据列表
*/
public List<Integer> getIds(Integer id){
return Arrays.asList(0,0,0);
}
/**
* 模拟不带参数从数据库查询简单数据类型数据列表
*/
public List<Integer> getIdsWithoutArgs(){
return Arrays.asList(0,0,0);
}
}
四、测试验证
测试验证的主要步骤如下所示。
(1)启动Redis
启动Redis,这里我直接在本地启动一个Redis服务,IP地址为127.0.0.1,端口为6379。
(2)配置application.yml
在项目的src/main/resources目录下创建application.yml文件,配置如下内容。
spring:
application:
name: redis-plugin
redis:
database: 0
host: 127.0.0.1
port: 6379
password:
timeout: 30000
lettuce:
pool:
enabled: true
max-active: 8
max-idle: 8
min-idle: 0
max-wait: 5000
address: redis://127.0.0.1:6379
cache:
type:
distribute: redis
distribute:
type:
lock: redisson
redis:
arrange:
type: single # single or cluster
(3)运行单元测试
运行DistributeCacheServiceTest类的所有代码,运行结果如下所示。

从测试结果来看,高性能Redis组件对外提供的接口方法所有单元测试用例全部验证通过,并且打印的结果数据也符合我们的预期。
注意:这里,我们是实际访问Redis进行的单元测试,在实际工作中,编写单元测试一般是通过Mock方式进行的,单元测试代码不允许依赖外部环境资源,例如,不允许依赖数据库、Redis等。关于如何使用Mock编写单元测试,后续我会单独开一个专栏专门讲解,这里就不再赘述。
五、本节总结
本节,主要对高性能Redis组件提供的核心功能进行了单元测试,主要是对高性能Redis组件对外提供的接口方法进行了全面的单元测试,测试结果符合我们的预期。
最后,可以在评论区写下你学完本章节的收获,祝大家都能学有所成,我们一起搞定高性能Redis组件。
六、写在最后
在冰河的知识星球除了热更的AI大模型外,还有其他十几个项目,像实战AI大模型、手写高性能敏组件、手写线程池、手写高性能SQL引擎、手写高性能Polaris网关、手写高性能熔断组件、手写通用指标上报组件、手写高性能数据库路由组件、手写分布式IM即时通讯系统、手写Seckill分布式秒杀系统、手写高性能RPC、实战高并发设计模式、简易商城系统等等。
这些项目的需求、方案、架构、落地等均来自互联网真实业务场景,让你真正学到互联网大厂的业务与技术落地方案,并将其有效转化为自己的知识储备。
值得一提的是:冰河自研的Polaris高性能网关比某些开源网关项目性能更高,目前正在热更AI大模型项目,也正在实现MCP,实战AI大模型正在热更中,全程带你分析原理和手撸代码。
你还在等啥?不少小伙伴经过星球硬核技术和项目的历练,早已成功跳槽加薪,实现薪资翻倍,而你,还在原地踏步,抱怨大环境不好。抛弃焦虑和抱怨,我们一起塌下心来沉淀硬核技术和项目,让自己的薪资更上一层楼。

目前,领券加入星球就可以跟冰河一起学习《DeepSeek大模型》、《手写高性能脱敏组件》、《手写线程池》、《手写高性能SQL引擎》、《手写高性能Polaris网关》、《手写高性能RPC项目》、《分布式Seckill秒杀系统》、《分布式IM即时通讯系统》《手写高性能通用熔断组件项目》、《手写高性能通用监控指标上报组件》、《手写高性能数据库路由组件》、《手写简易商城脚手架项目》、《Spring6核心技术与源码解析》和《实战高并发设计模式》,从零开始介绍原理、设计架构、手撸代码。
花很少的钱就能学这么多硬核技术、中间件项目和大厂秒杀系统与分布式IM即时通讯系统,比其他培训机构不知便宜多少倍,硬核多少倍,如果是我,我会买他个十年!
加入要趁早,后续还会随着项目和加入的人数涨价,而且只会涨,不会降,先加入的小伙伴就是赚到。
另外,还有一个限时福利,邀请一个小伙伴加入,冰河就会给一笔 分享有奖 ,有些小伙伴都邀请了50+人,早就回本了!
七、其他方式加入星球
- 链接 :打开链接 http://m6z.cn/6aeFbs 加入星球。
- 回复 :在公众号 冰河技术 回复 星球 领取优惠券加入星球。
特别提醒: 苹果用户进圈或续费,请加微信 hacker_binghe 扫二维码,或者去公众号 冰河技术 回复 星球 扫二维码加入星球。
好了,今天就到这儿吧,我是冰河,我们下期见~~
