当前位置: 首页 > 科技观察

大淘宝用户平台技术团队单元测试建设

时间:2023-03-16 11:02:55 科技观察

单元测试是项目交付前质量保证的第一环节,无疑是软件工程质量保证的重要基石。有效的单元测试可以提前发现90%以上的代码错误,同时还可以防止代码损坏,这对工程重构的演化起到了至关重要的作用。为什么需要单元测试纵观优秀的开源项目,完整的单元测试总是必不可少的。通过这些单元测试,我们可以充分了解代码中相关类和方法的功能和核心逻辑,熟悉各种场景的操作。同时,由于进行了单元测试,开源作者在接受各种特性的代码提交时可以保证稳定性和安全性。其实所有开发同学都应该知道单元测试的重要性。同样,TDD(TestDrivenDevelopment)并不是一个新概念,但是当我们将其付诸实践时,总会发现各种原因。说服自己下次好好写单元测试,这次就放手吧。这些原因无非是开发周期太紧;测试学生可以保证函数的正确性;编写单元测试代码比业务代码大;跑起来也不是不可能。所以虽然我们一直在追逐工程师文化,但时不时也会沉溺于放弃工程师背景的路上。单元测试是项目交付前质量保证的第一个环节,无疑是软件工程质量保证的重要基石。有效的单元测试可以提前发现90%以上的代码错误,同时防止代码损坏。结构演进中起着至关重要的作用。如何写单元测试?好的单元测试的几个要点摘自阿里巴巴开发规范。单元测试必须遵守AIR原则。是全自动和非交互式的。测试用例通常定期执行,执行过程必须完全自动化才有意义。输出需要人工检查的测试不是好的单元测试;单元测试应该保证测试粒度足够小。单元测试测试粒度足够小以帮助查明问题。单元测试粒度最多是类级别,通常是方法级别;单元测试必须遵守BCDE原则,边界、边界值测试,包括循环边界、特殊值、特殊时间点、数据顺序等;正确,正确的输入,得到预期的结果;设计,结合设计文档编写单元测试;Error,强制错误信息输入(如:非法数据、异常流程、非业务允许输入等),得到预期结果;核心业务、核心应用、核心模块的增量代码必须保证单元测试通过;?单元测试编码范式这里主要使用Mockito单元测试框架作为模板Mock:通过when().thenReturn/thenAnswer/thenThrow或doReturn().when()等mock方法模拟依赖类方法,模拟服务依赖或中间结果DO:调用被测类方法,执行测试链接Verify:验证执行结果的正确性,通过Assert验证数据结果的准确性,通过Verify验证链接执行的准确性,检查通过expected=Exception.class的异常链接publicclassTest{//0.依赖类@MockDependencyClassdependencyClass;//0.待测类@InjectMocksTestClasstestClass;@BeforepublicvoidsetUp(){MockitoAnnotations.initMocks(this);}@TestpublicvoidtestMethod(){//1.mock,依赖方法,构造中间层数据when(dependencyClass.someMehod(any())).thenReturn(mockData());//2.做,调用被测类Resultresult=testClass.testMehod();//3.验证,验证结果数据Assert.assertEquals("someexpectedresultstring",result.getModel());}}当然,虽然编写单元测试用例的套路比较模板化,但我们也要充分利用单元测试框架(Junit/Mockito/PowerMock/Spock),掌握一些技巧,才能写得又快又准无情的单元测试用例。研发同学必须掌握的基本技能如何使用单元测试框架在此不再赘述(详见阿里技术♂)。?单元测试编码效率IDEA上有很多单元测试插件,可以半自动生成单元测试类文件。这里推荐使用TestMe插件。TestMe插件可以智能分析被测类的依赖类,结合Mockito+Junit等单元测试框架,生成Mock/InjectMocks依赖,自动生成单元测试类。假设业务代码如下:@ComponentpublicclassDefaultMemberManagerimplementsMemberManager{@AutowiredprivateMemberDAOmemberDAO;@AutowiredprivateCacheManager缓存管理器;@OverridepublicDatequeryActivationTime(longuserId){DateactivationTime=cacheManager.getTimeif==niuseractivationTimeif(Id);){MemberDOmemberDO=memberDAO.queryByUserId(userId);如果(memberDO!=null){cacheManager.saveActivationTime(userId,memberDO.getActiveTime());activationTime=memberDO.getActiveTime();}}返回激活时间;}}然后通过TestMe快捷键COMMOND+N,可以自动生成下面的单元测试类publicclassDefaultMemberManagerTest{@MockMemberDAOmemberDAO;@MockCacheManager缓存管理器;@InjectMocksDefaultMemberManagerdefaultMemberManager;@BeforepublicvoidsetUp(){MockitoAnnotations.init;Mocks(this)}@TestpublicvoidtestQueryActivationTime()throwsException{when(memberDAO.queryByUserId(anyLong())).thenReturn(null);when(cacheManager.getActivationTime(anyLong())).thenReturn(newGregorianCalendar(2022,Calendar.MARCH,5,23,2).getTime());日期结果=defaultMemberManager.queryActivationTime(0L);Assert.assertEquals(newGregorianCalendar(2022,Calendar.MARCH,5,23,2).getTime(),结果);}}团队单元测试构建?覆盖率概念覆盖率是通过javaagent挂载类JaCoCo插件的方式,在单元测试命令运行时进行代码覆盖率检测,计算单元测试执行期间代码覆盖率产生覆盖。常见的覆盖指标又可以细分为语句覆盖、条件覆盖、分支覆盖、路径覆盖等,这里目前比较关注语句覆盖和分支覆盖,尤其是增量代码覆盖,更能体现单元测试更改代码的覆盖率。?如何进行单元测试这里依赖阿里研发平台Aone的测试实验室功能。Aone实验室支持测试任务插件的编排组合,通过独立的测试资源执行测试任务。所以我们对代码拉取插件、单元测试插件和覆盖率计算插件进行整理配置,形成最终的执行流程:拉取代码;执行单元测试命令;分析单元测试结果;计算覆盖率。最后完成整个项目的单元测试覆盖率计算。单元测试覆盖率结果示例如下:?何时触发单元测试单元测试任务主要通过持续交付流水线集成。目前主要的触发策略有:提交代码时,保证单元测试执行的及时性。审核通过的代码分支符合单元测试标准。在发布过程中,确保最终集成发布的所有分支代码都符合单元测试标准。?单元测试覆盖率卡住了。用户平台技术团队单元测试规范如下:单元测试用例通过率为100%unit增量测试代码行覆盖率为85%代码规范扫描增量问题总数为0?UnitTestCoverageReportIn为了更好地衡量单元测试的覆盖率,我们采用报表的形式统计每个应用、每个团队的代码单元测试覆盖率。综上所述,到2022年,当前团队各应用(边缘应用除外)单元测试增量代码覆盖率达到85%标准,最新平均增量代码行覆盖率达到88%,整体全代码覆盖率达到85%。平均增长了20%%。诚然,提高单元测试覆盖率并不是最终目标。覆盖率高并不能完全代表项目质量高,但没有单元测试或单元测试覆盖率低的项目,代码质量和稳定性一定不高。同时,团队中的研发同学也对单元测试有了新的认识,自测和测试质量明显提升。全年无因代码质量问题上线,有效提升了项目质量和服务稳定性。后续规划,持续优化单元测试质量,提升分支覆盖,优化边界异常覆盖;关注单元测试编码效率的提升,优化测试用例与测试数据的分离;关注核心环节单元测试覆盖率;巧妙地将TDD思维运用到业务开发过程中。团队介绍大淘宝技术-用户平台技术团队是集研发、数据、算法为一体的团队,负责淘宝用户增长、游戏互动、平台会员、私域运营等消费者核心业务。团队肩负着保卫电商主业增长的重要使命,是阿里核心电商战场的参与者。它用不断的技术创新来驱动阿里电商引擎的稳步前进。这是一个年轻开放的团队,在这里你将获得超大规模、高并发场景的架构设计能力,洞察最前沿的用户增长实战方法,获得数字时代的核心竞争力.团队技术氛围浓厚,崇尚创新和工程师文化,鼓励使用数据和代码发现和解决问题。团队研发流程规范,代码质量高,学习成长速度快。