交易平台这一年进行了几次大规模的迁移工作,从最开始的商品域,到订单域,现在订单退换货(RMA)的迁移也已经完成。虽然几个系统现在在线上已稳定运行,但是在测试过程中还是碰到了一些问题的,在此做个简要的总结,以便之后类似的项目借鉴。
迁移的测试范围大致可以分为:数据一致性测试、接口逻辑测试、功能测试、数据同步测试、性能测试 。上线前还进行了与各相关业务方间的预演,及回滚方案的预演。
数据一致性测试
由于迁移需要做到调用方无感,因此数据一致性显得尤为重要,在此块我们做了 .net 与 java 接口请求参数一致性对比、返回值一致性对比及 DB 数据的一致性对比。
我们用 python 自动化脚本实现此块测试,引入了 python 语言的装饰器概念,通过传递环境参数以指定测试用例运行的环境,以做到迁移结束后可简单的通过只修改环境参数而实现自动化脚本的复用,如下图所示。
-
defdeco_compare(env=1,db_compare=False,ex='',db_ex='',
-
no_additional=False,ex_only_none=False,
-
is_none_equal_empty=False):
-
defdeco_resp(func):
-
@wraps(func)
-
defwrapper(*args,**kw):
-
print'执行用例 %s():'%func.__name__
-
func_result_one =None
-
func_result_two =None
-
# 只调用java创建订单接口,不进行任何比对
-
ifenv ==1:
-
...
-
# 只调用dotnet创建订单接口,不进行任何比对
-
elifenv ==2:
-
...
-
elifenv ==3orenv ==4:
-
# 先调用java接口,后调用dontnet接口,并比对返回值
-
ifenv ==3:
-
...
-
# 用于query-order中部分接口是从其他服务迁入的情况
-
elifenv ==4:
-
...
-
# 如果要求不进行数据库对比,只比对response
-
ifdb_compare isFalse:
-
...
-
# 如果进行数据库比对,先比对response,再对比数据库查询数据
-
elifdb_compare isTrue:
-
...
-
returnfunc(*args,**kw)
-
returnwrapper
-
returndeco_resp
测试过程中,主要是使用 env = 3 或 4 的情况,在进行数据对比时,我们使用了 json_tools 工具,可以对传入的两个 json 体进行对比,并打印出值与类型的差异、属性名的差异。
实现的步骤为:
-
接口在 java 环境中请求一次,记录结果
-
相同参数在 .net 环境中请求一次,记录结果
-
去除无需对比的字段(如新建订单时生成的订单号)后,对比 1、 2 的结果是否相同
-
MySQL 中查询需要校验的字段,记录结果
-
在一定的 mapping 规则下,根据上一步的 SQL 查询语句生成 SQLServer 中可以使用的语句,进行查询,并记录结果
-
去除无需对比的字段后,对比 4、 5 的结果是否相同。
通过此方法,我们可以保证迁移之后的接口及 DB 数据结构与迁移前的相同。
接口逻辑测试
商品系统、订单系统及 RMA 系统所提供的大部分为接口,所以接口逻辑的测试不仅是迁移过程中的重点,更是日常测试中最为关注的部分。
以订单系统为例,测试需要覆盖下单、改单、配送、确认收入、查询等功能模块,下单中又包含了 14 种商品类型、 24 种订单类型及 8 种促销优惠方式。
如何将如此复杂的场景覆盖全面,是我们在测试之初讨论最久的问题,最后经过几次的讨论,我们确定了覆盖的流程,以商品类型作为大的划分,加入组合的促销方式,生成对应的订单类型。
由于测试的很多场景具有相似性,我们在脚本中大量采用了参数化的方式传递不同类型的数据,使代码简洁并很大程度上减轻了工作量。
我们还把一些很通用的业务功能抽取出来,比如不同类型的基础订单创建、订单收入的验证等,以供流程脚本中直接调用。
这部分的测试贯穿了整个测试过程,保证了上线后并没有出现流程性的问题。
功能测试
交易平台并没有太多外显的功能测试需求,但是功能是用户最先所见的部分,因此后台的功能测试也是极其重要的。后台功能的使用者主要为客服、运营及财务等,因此在测试前先与产品进行了沟通,列出了功能测试部分的测试要点,上线后并没有出现大的异常。
数据同步测试
此次不仅包含了程序代码从 .net 平台到 java 的迁移,也包含了数据库从 SQLServer 到 MySQL 的迁移。
数据同步包含了起初的全量数据同步(dataX),及增量数据的反向同步(yugong),这保障了上线后用户数据不会丢失,也保障了万一出现回滚操作时 SQLServer 及 MySQL 数据的一致。
由于每次同步的日志很多,且遍布不同的文件夹,因此我们通过脚本分析同步的日志,打印出所有的异常,上线后未出现因数据不一致而产生的问题。
性能测试
性能测试的重要性是毋庸置疑的,尤其是上线时双十一双十二的活动近在咫尺,订单域的压力可想而知。
横向团队帮忙做了重要接口的压测,我们自己也对主要的流程及核心功能做了业务逻辑侧的并发测试。
ThreadPool 库可以很方便的实现并发的需求,如下:
-
importthreadpool
-
defrun_thread_pool(self,threads_num,request_num,target_request):
-
"""
-
用于创建线程池
-
:param threads_num: 线程数量
-
:param request_num: 发送请求次数
-
:param target_request: 需要运行的函数
-
:return:
-
"""
-
pool =threadpool.ThreadPool(threads_num)
-
requests =threadpool.makeRequests(target_request,request_num)
-
[pool.putRequest(req)forreq inrequests]
-
pool.wait()
通过传入线程数及请求总量,并结合我们现有的自动化脚本来实现并发测试。
业务方验收
这是上线前相当重要的一个步骤,主要就是通过模拟真实的操作及早暴露问题。
交易平台的几个系统涉及到的业务方较多,为了确保上线的稳定,类似的大项目迁移需要业务方在测试环境就进行验收,并在 yz 环境进行主要功能的预演。
我们同大网校、 享互进行了几场预演,在预演前与业务方一起列出了有代表性的场景,并召集相关的人员坐在一起进行全流程的操作,也请到了财务,客服及 BI 部门一起帮忙验收核对数据。
预演的过程中发现了一些测试过程中未发现的问题,当这些问题修正并再次预演成功后,让我们对上线后的质量更加有了信心, 事实证明预演为我们顺利上线提供了强有力的保障。
回滚预演
为了应对上线时万一出现的重大问题,回滚方案的预演也是必不可少的, 当然上线很顺利,并未使用到回滚的操作,可是也需要提前做好充足的准备。
难点及对应方案
-
对业务的不熟悉:测试人员进入交易平台的时间都不超过 3 个月,没有人对整体业务有清晰的了解,只能通过边测边熟的过程查缺补漏,好在有产品及开发的鼎力相助,帮忙一起梳理测试要点,这个时候开发出的流程图、时序图及单元测试都起到了很大的帮助,让我们能够以最快的速度熟悉业务;
-
任务多人员紧:以订单系统为例,测试人员一共有 4 人,中间还穿插了沪江网校周年庆活动压测、分销测试及一些常规优化的测试,使得本来就紧张的迁移测试更为严峻。我们做了以下几点来应对这个问题:
-
测试准备工作与开发过程同步开始,准备期间完成大部分的单接口的自动化脚本;
-
在熟悉了单接口逻辑及业务逻辑后,及时补充流程脚本;
-
测试过程中及时暴露问题及风险,发起会议和开发产品一起讨论解决方案
-
了解 bug 产生的原因,以便合理推测可能产生的影响点,并能对系统逻辑更加熟悉;
-
提早寻找外援帮忙测试;
-
合理安排加班时间,松弛有度才能保持高效率;
-
技术方案定夺:对于数据一致性的测试,前期想了很多方法,最终确定了使用装饰器的方式封装数据对比方法,虽然这部分耗时较久,但是这为之后的验证奠定了坚实的基础。
系统迁移的测试过程很艰辛,但当订单系统的停服上线时间仅用了预期的 38%、RMA 系统的停服上线时间提前了一天以及上线后各系统的稳定运行都将我们的这份艰辛都化为了成就感。
自动化脚本在测试过程中起到了很大的作用,我们必须要明确的知道系统的运行逻辑,验证每一步操作会影响到的字段,这同时加速了我们熟悉业务的过程,比如验证订单收入时,我们了解了不同商品不同促销规则不同订单类型计算金额分摊的规则,比如预售类型的订单,我们了解了定金单尾款单在数据库中的不同体现,等等 。
在一致性的测试中,脚本也大大的减轻了我们的工作量,新技术的引入使得测试过程更高效,结果更准确,完全避免了手工测试时肉眼造成的测试误差,这段时间大量的脚本也让我们对自动化框架更加熟悉,使得之后的脚本写起来更顺畅,后期拼团项目的快速稳定上线也得力于这段时间的累积。
交易平台后续还有很多大型的项目,相信这段时间的成长以及不断的新技术学习都将为后续的项目领航。