卓越工程之单元测试在行权鉴权中的实践

2022 年 10 月 21 日 阿里技术


前言


在去年的时候就读过《重构:改善既有代码的设计》这本在代码重构领域里的经典,当时在读的时候就苦于有这么两点导致只停留在了“读”上面,而缺少实践。 

1.全书内容比较枯燥乏味,虽然有部分代码示例,但是语言并不生动,让人坚持读下去就很难。

2. 书中强调,每做一次代码的重构,即使修改很小的部分,也应该对修改进行测试,所以在看到书中举例的各种重构和重构后的不断测试时,就对测试和重构打起了退堂鼓
 因为对代码的测试缺少整体的认知,对单元测试也一直停留在简单的print层面,直到在这几天通过一个阅读打卡活动,系统性的学习了大量关于单元测试的理论、实践知识和在代码重构中的帮助,重新让我回忆起《重构》书中所提到的知识点,一直跃跃欲试,所以也想尝试将单元测试实际应用在自己写的业务代码中,为自己的代码“保驾护航”,同时在代码中有单测,在重构的过程中单测也会让自己不慌张,修改代码后直接执行一下单测就可以对修改后的准确性进行验证。这篇文章着重在“实践”上,是对 Java编程技巧之单元测试用例编写流程 这篇文章的实际应用,并没有高深的理论和技术。

流程


包括单元测试在内的所有测试都应该对所需要测试的流程有比较清晰的认识才能保证测试的用例不被遗漏,保证测试质量,因此在撰写单元测试前,首先需要对所测试部分代码的流程进行梳理。 



1.用户发起查询时,首先判断用户传入的参数中是否包含行权验证的字段,如果不包含则直接抛出异常,提示鉴权失败;

2. 在鉴权中,因为行权可能会由多个字段组合鉴权,因此需要对全部鉴权字段进行遍历。在鉴权时,还会有匹配字段,包含:
  • 等值匹配(=)

  • 前缀匹配(like xxx%)

  • 后缀匹配(like %xxx)

  • 模糊匹配(like %xxx%)

四种形式,当用户输入参数与匹配字段不相符时,记作鉴权失败。
3. 当用户没有输入参数中的权限时,记作鉴权失败。
4. 在多个鉴权字段进行组合时,还会存在两种组合逻辑:and(所有字段均需要有权限才能访问)和 or(任意字段有权限即可访问),所以还会结合组合逻辑进行综合权限判定。

测试边界


在明确了代码的流程后,就需要对测试边界进行明确,测试应该着重对边界情况进行测试,因为清晰的单元测试边界划分有利于构建更加稳定的系统核心代码,因为我们在推进测试边界的过程中会不断地将副作用从核心代码中剥离出去,最终会得到一个完整且可测试的核心,而我们的核心代码就是处于测试边界内的。下图将所有的情况做了枚举,作为单元测试的用例。 



撰写单元测试


引入依赖

  
  
    
<dependency>    <groupId>org.powermock</groupId>    <artifactId>powermock-core</artifactId>    <version>${powermock.version}</version>    <scope>test</scope></dependency><dependency>    <groupId>org.powermock</groupId>    <artifactId>powermock-api-mockito2</artifactId>    <version>${powermock.version}</version>    <scope>test</scope></dependency><dependency>    <groupId>org.powermock</groupId>    <artifactId>powermock-module-junit4</artifactId>    <version>${powermock.version}</version>    <scope>test</scope></dependency>
  
  
    
其中,powermock.version为2.0.9,为当前的最新版本,可根据实际情况修改。在PowerMock包中,已经包含了对应的Mockito和JUnit包,所以无需单独引入Mockito和JUnit包。

模拟方法

1. 首先是需要对外部依赖和进行测试的类进行模拟和注入:
    // 需要模拟的外部依赖    @Mock    private ArkDataSetReadService arkDataSetReadService;        // 需要进行测试的类    @InjectMocks    private ComponentJobExecuteService componentJobExecuteService;
2. 之后就是对依赖的方法进行模拟:
Response<RowPermissionQueryResponseDto> response = JSON.parseObject(permissionData, Response.class);
Mockito.doReturn(response).when(arkDataSetReadService).getUserRowPermissions(911L, 1741141);
  
  
    

通过文本的方式构造模拟的返回值。

通过Mockito.doReturn() 方法模拟调用时的返回值。
3. 最后就是对所测试的方法进行测试:
Map<String, Pair<String, List<String>>> filterParams = new HashMap<>();

Whitebox.invokeMethod(componentJobExecuteService, "checkRowPermission", 911L, filterParams)
  
  
    

完整的测试代码:
    @Test(expected = AuthException.class)    public void testRowPermission() throws Exception {               ContextInfo contextInfo = new ContextInfo();        contextInfo.setBucId(1741141);        ContextInfoHolder.setContextInfo(contextInfo);               Response<RowPermissionQueryResponseDto> response = JSON.parseObject(permissionData, Response.class);
Mockito.doReturn(response).when(arkDataSetReadService).getUserRowPermissions(911L, 1741141);
Map<String, Pair<String, List<String>>> filterParams = new HashMap<>();
Whitebox.invokeMethod(componentJobExecuteService, "checkRowPermission", 911L, filterParams); }
因为在没有权限的时候会直接抛出 AuthException,所以通过@Test(expected = AuthException.class) 进行验证。
 到此,行权验证的单元测试框架就初步搭建完成,接下来就是根据前面梳理的单元测试用例的边界构建不同的参数进行验证。

总结


在实际撰写单元测试时,由于对工具的不熟悉担心写起来比较麻烦,所以一直没进行尝试,但是在实际操作的时候发现,在写单元测试的时候,其实也是对整个代码进行梳理的过程,是对自己写代码时思路的复盘和总结,单测不只是能验证代码执行的准确性,还能验证在写代码时的逻辑是否正确、能否满足业务的实际需求。
有了单测打底,接下来即使需要对这部分代码进行重构、迭代,也能做到心中有数,只需要在重构完成后执行下单测就可以轻松验证代码的准确性。
希望能够通过这次实践,能够让自己在写单测的路上坚持下去。

往期推荐

1.聊一聊分布式锁的设计模型

2.阿里10年沉淀|那些技术实战中的架构设计方法


《Java工程师必读手册》


工匠追求“术”到极致,其实就是在寻“道”,且离悟“道”也就不远了,亦或是已经得道,这就是“工匠精神”——一种追求“以术得道”的精神。如果一个工匠只满足于“术”,不能追求“术”到极致去悟“道”,那只是一个靠“术”养家糊口的工匠而已。作者根据多年来的实践探索,总结了大量的Java编码之“术”,试图阐述出心中的Java编码之“道”。


点击阅读原文查看详情。

登录查看更多
0

相关内容

【2022新书】构建微服务:设计细粒度系统,615页pdf
专知会员服务
89+阅读 · 2022年9月4日
Neo4j知识图谱的技术解析及案例分享
专知会员服务
46+阅读 · 2022年7月15日
【经典书】多处理器编程艺术,562页pdf
专知会员服务
66+阅读 · 2022年7月10日
【干货书】Python3编程高级指南,494页pdf
专知会员服务
90+阅读 · 2022年5月18日
专知会员服务
91+阅读 · 2020年12月26日
【2020新书】高级Python编程,620页pdf
专知会员服务
235+阅读 · 2020年7月31日
5个编写技巧,有效提高单元测试实践
阿里技术
0+阅读 · 2022年11月17日
如何写出有效的单元测试
阿里技术
0+阅读 · 2022年8月25日
客户端单元测试实践——C++篇
阿里技术
0+阅读 · 2022年8月2日
代码重构:面向单元测试
阿里技术
0+阅读 · 2022年7月29日
淘系用户平台技术团队单元测试建设
阿里技术
0+阅读 · 2022年5月12日
Go应用单元测试实践
阿里技术
0+阅读 · 2022年4月8日
腾讯课堂小程序开发实践与思考
InfoQ
0+阅读 · 2022年3月27日
工程设计论——如何写好工程代码
阿里技术
0+阅读 · 2022年2月15日
谈一谈单元测试
阿里技术
0+阅读 · 2022年2月14日
国家自然科学基金
0+阅读 · 2013年12月31日
国家自然科学基金
2+阅读 · 2013年12月31日
国家自然科学基金
0+阅读 · 2012年12月31日
国家自然科学基金
0+阅读 · 2012年12月31日
国家自然科学基金
0+阅读 · 2012年12月31日
国家自然科学基金
1+阅读 · 2012年12月31日
国家自然科学基金
0+阅读 · 2010年12月31日
国家自然科学基金
0+阅读 · 2009年12月31日
国家自然科学基金
0+阅读 · 2009年12月31日
已删除
Arxiv
32+阅读 · 2020年3月23日
Arxiv
15+阅读 · 2020年2月5日
VIP会员
相关VIP内容
【2022新书】构建微服务:设计细粒度系统,615页pdf
专知会员服务
89+阅读 · 2022年9月4日
Neo4j知识图谱的技术解析及案例分享
专知会员服务
46+阅读 · 2022年7月15日
【经典书】多处理器编程艺术,562页pdf
专知会员服务
66+阅读 · 2022年7月10日
【干货书】Python3编程高级指南,494页pdf
专知会员服务
90+阅读 · 2022年5月18日
专知会员服务
91+阅读 · 2020年12月26日
【2020新书】高级Python编程,620页pdf
专知会员服务
235+阅读 · 2020年7月31日
相关资讯
5个编写技巧,有效提高单元测试实践
阿里技术
0+阅读 · 2022年11月17日
如何写出有效的单元测试
阿里技术
0+阅读 · 2022年8月25日
客户端单元测试实践——C++篇
阿里技术
0+阅读 · 2022年8月2日
代码重构:面向单元测试
阿里技术
0+阅读 · 2022年7月29日
淘系用户平台技术团队单元测试建设
阿里技术
0+阅读 · 2022年5月12日
Go应用单元测试实践
阿里技术
0+阅读 · 2022年4月8日
腾讯课堂小程序开发实践与思考
InfoQ
0+阅读 · 2022年3月27日
工程设计论——如何写好工程代码
阿里技术
0+阅读 · 2022年2月15日
谈一谈单元测试
阿里技术
0+阅读 · 2022年2月14日
相关基金
国家自然科学基金
0+阅读 · 2013年12月31日
国家自然科学基金
2+阅读 · 2013年12月31日
国家自然科学基金
0+阅读 · 2012年12月31日
国家自然科学基金
0+阅读 · 2012年12月31日
国家自然科学基金
0+阅读 · 2012年12月31日
国家自然科学基金
1+阅读 · 2012年12月31日
国家自然科学基金
0+阅读 · 2010年12月31日
国家自然科学基金
0+阅读 · 2009年12月31日
国家自然科学基金
0+阅读 · 2009年12月31日
Top
微信扫码咨询专知VIP会员