摘要:本文介绍了一种针对关系型数据库的复杂计算代码逻辑测试方法,该方法借助关系型数据库提供的存储过程服务,可以在不依赖代码逻辑的情况下,直接编写自动验证用例,并保存整个计算流程的中间计算结果,提供简单可依赖运算正确性质量保证。
1 引言
在许多报表和统计类产品中,存在大量的复杂计算功能,这些公式往往有数十步的计算过程,上万条数据统计记录,以及跨多个关系型数据库的数据依赖,甚至是多种语言的混合实现。更棘手的是:往往为了节省数据存储资源,数据库不存储这些复杂计算逻辑的中间结果,而是直接存储最终计算结果,为前端提供数据。
在运营产品“盘古”系统中,为了衡量一个销售人员近期的业绩情况,要经过一系列的统计和计算为每个销售人员打一个综合评分,根据综合评分对销售人员分配销售任务,整个公式如下(具体业务参数和公式内涵与本文主题无关,不再冗述):
上面列举的计算还不包括大量的查询、排序、求最大值和最小值、求平均值等逻辑运算。在持久层的设计中,从原始的数据记录到最终的得分,中间没有存储任何的计算过程中间值,这点设计上没有问题,任何数据型系统都应该在不影响性能的情况下尽量节约存储空间。但是,复杂的运算导致了功能实现的软件质量风险,也给QA设计相应的测试用例带来的一定困难,下文将详细介绍,该类问题的测试解决方案。
2 针对复杂计算功能的测试方法
对于此类复杂计算的功能测试,一般采用以下两种方式进行测试:
(一) 手工用例核算的测试方法。账单、财务报表等系统的测试,QA很多采用这种手工核算的测试方法,对每一个计算项目进行手工计算核对,以此来保证代码逻辑的计算正确性。但是这种愚公移山的办法,用在上述这种没有计算过程中间值的情况下,就十分不可靠而又低效了。第一,对于万级别以上的数据查询、排序,求最大值、最小值和平均值都是不可能完成的任务;第二,即使我们结合SQL语句进行查询、排序等逻辑运算,计算结果经过上述10个公式的手工计算难以保证用例计算的正确性;第三,手工计算效率太低且成功率没有保障,每次升级后,回归测试人力开销太大。
(二) 基于单元测试框架的测试方法。这种方法是对各个逻辑接口进行插桩,根据条件分支通过等价类划分和排列组合设计各种条件组合用例来进行测试。这种方式复用性强,用例可长期维护和自动化回归测试,是种较好的解决方案。但是,对于一些数据依赖性强的系统,需要大量准备测试数据,且这些数据互相之间有逻辑关联,数据构造带来了很大的工作量,并且还要对数据本身进行验证,降低了测试效率。
3基于存储过程的测试方法
上述两种方案为目前针对复杂计算功能所最常采用的三种方法,各有长短优劣。在盘古系统相关模块的测试中,结合了手工核算的手工用例和基于单元测试框架的自动化用例的测试思想,采用了一种基于存储过程的自动测试结合手工核算的方法,实现的基本思路如下:
Step 1. 将复杂的数学计算逻辑拆分成若干个计算片段,保证每个计算片段都可以较容易的计算出来,每个计算片段生成一个中间值。
Step 2. 在测试环境中,如表1所示,构建一张测试数据表,除ID外,为每个计算片段设置一个表字段,用于存储每个记录的计算片段中间值。
Step 3. 按照Step 1拆分的计算片段逻辑,直接使用数据库存储过程实现整个计算过程,数据查询、排序,求最大值、最小值和平均值等运算都可以方便的使用数据库提供的接口,且存储过程支持变量和游标,逻辑实现起来十分简便。
Step 4. 测试执行时,流程如图1所示,先执行被测功能代码逻辑,再基于同一个数据源执行存储过程的测试用例,最后对比测试表最终计算结果和被测功能代码逻辑的计算结果。如果出现测试用例和代码逻辑计算不一致的情况,QA可根据计算过程,方便的进行手工核对,定位出错点时测试用例还是代码逻辑。若用例出错,及时修正测试用例;若测试用例没有出错,则可以根据计算过程的中间值,结合debug工具,定位代码逻辑的bug点。
这种基于存储过程的测试方式总结下来有以下优势:
(一) 与基于单元测试框架的方法相比,实现起来简单、轻量、高效。直接面向数据库进行操作,不依赖原有代码逻辑和第三方框架,开发用例代码量小,。
(二) 在测试表中留下计算全过程,方便错误的跟踪。
(三) 与手工核算的方法相比,本测试方法QA时间开销主要在测试设计阶段,测试执行时间短,且便于维护,方便自动化回归测试。
由于盘古项目的计算流程较为复杂且需要许多业务相关知识,这里为举一个简化的模拟场景来说明本文所述基于存储过程的测试方法。表2为原始记录数据表(tb_os_log),记录了销售人员工作拜访日志,
表3为销售人员得分表(tb_os_point),这个表已经预先存入参加评分的销售ID,
下面两个公式(5)是从原始记录到实际得分的计算公式,
其中, 为在 到 时间段内销售人员拜访任务总量, 为销售人员的成交订单数量, 为转化率, 为销售人员中的最高转化率, 为销售人员中的最低转化率, 为最终销售人员的得分。被测计算功能是将tb_os_log通过上述数学计算得到结果,并存入tb_os_point表的total_point字段。
测试时,首先设计并创建测试表(tb_os_test),表4为测试表的各字段说明,is_pass字段为0本条数据通过测试,is_pass字段为1本条数据测试不通过。