作者:京东物流 刘红妍
导读:在自动化测试实际中,为了更好的符合被测业务场景,须要一直优化框架分层构造。本文联合产品模块化思路,意在介绍通过策略模式革新本来简单分支语句代码,通过实践解说、思路剖析、方案设计、及代码演示,提供自动化脚本重构的落地计划。
01 痛点
在往年的麻利团队建设中,我通过 Suite 执行器实现了一键自动化单元测试。Juint 除了 Suite 执行器还有哪些执行器呢?由此我的 Runner 探索之旅开始了!
随着运输业务场景的不断丰富和自动化脚本量的一直累积,日常在 review 用例时发现,目前大家仍停留在针对需要定制化用例编写,无奈进步用例可复用性和可编排性。当业务流程两头某一环节发生变化时,岂但须要从新批改脚本,还会影响以后利用其余用例执行后果。所以,如何设计高复用性脚本成为目前自动化建设的要害节点。
02 设计实践*
了解,首先 MCube 会根据模板缓存状态判断是否须要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的构造,转换实现后将通过表达式引擎解析表达式并获得正确的值,通过事件解析引擎解析用户自定义事件并实现事件的绑定,实现解析赋值以及事件绑定后进行视图的渲染,最终将指标页面展现到屏幕。从设计稿登程,晋升页面搭建效率,亟需解决的外围问题有:
2.1 设计理念 *
依据面向对象程序设计理念,设计者应遵循高内聚与低耦合准则,通常程序结构中各模块的内聚水平越高,模块间的耦合水平就越低。高内聚意味着一个类所能提供的性能应该是相干的,即一个类不要设计得包含很多互不相干的性能,低耦合代表要正当布局模块的颗粒度,即要保障一个模块可独立存在,升高模块之间简单依赖关系。
2.2 策略模式**
策略模式定义了一系列的算法,将每一组相干的算法封装起各个策略分支,从而将分支相干的代码暗藏起来,并且使它们之间能够互相替换。策略模式让算法的变动不会影响到应用算法的客户,心愿能够进步程序的可扩展性。
03 解决思路
了解,首先 MCube 会根据模板缓存状态判断是否须要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的构造,转换实现后将通过表达式引擎解析表达式并获得正确的值,通过事件解析引擎解析用户自定义事件并实现事件的绑定,实现解析赋值以及事件绑定后进行视图的渲染,最终将指标页面展现到屏幕。从设计稿登程,晋升页面搭建效率,亟需解决的外围问题有:
3.1 基本思路
依据运输业务同一个流程存在不同场景,如询价服务接上游下发询价单节点,须要辨别起源执行不同逻辑,目前设计五个算法能力,依据前期业务一直扩大,还会有更多算法退出进来,这个时候须要思考一个好的构造对代码进行优化。可能后期大家通过 if…elif…else 分支语句就可实现,但在思考零碎的健壮性和可维护性,这里就不能大量应用 if 分支语句。因为每一种算法能力的代码量极大且算法参数几十个,在随着更多上游接入可能存在十几个甚至更多 else 分支,很容易顾此失彼,牵一发而动全身。所以,利用策略模式设计一系列算法,再供用例拼装调用,进步代码的可读性和可复用性。
3.2 计划剖析**
长处:
- 代码解耦,便于保护;
- 防止应用难以保护的多重条件抉择语句;
- 能够运行时动静切换算法;
- 开闭准则。毋庸对上下文代码进行批改,就能够增加新的代码。
毛病:
- 如果算法逻辑,较为固定,不常常批改,应用策略模式只会减少代码量
- 必须晓得所有的具体策略类及它们的区别。
04 计划概述
了解,首先 MCube 会根据模板缓存状态判断是否须要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的构造,转换实现后将通过表达式引擎解析表达式并获得正确的值,通过事件解析引擎解析用户自定义事件并实现事件的绑定,实现解析赋值以及事件绑定后进行视图的渲染,最终将指标页面展现到屏幕。
4.1 环境依赖
Laputa 框架简介:
Laputa 框架基于 Pytest 集成了对 API 接口自动化, 以及对 Web 利用, 挪动端利用和 Windows 桌面利用 UI 等自动化的能力。具备可视化的 Web 界面工具, 便于配置执行规定,关联执行脚本,触发用例执行,查看执行后果。提供 CI 集成服务,调用 Jenkins API 跟踪继续集成后果,凋谢接口,实现流水线自动化测试。
图 1 自动化框架架构图
4.2 分层革新**
图 2 自动化用例分层图
4.3 策略设计**
图 3 策略模式设计图
4.4 操作步骤**
- 将频繁批改的算法进行抽取,独立为具体的算法类;
- 创立形象基类,实现一个约定的形象策略办法;
- 所有独立的算法类,必须实现基类中的形象策略接口;
- 建设高低类,该类能够动静的对算法进行 setter,创立调用具体算法的办法,上下文可通过该办法与具体的策略交互;
- 客户端进行调用,传入具体的算法类,上下文动静执行具体的算法工作。
05 设计实际
了解,首先 MCube 会根据模板缓存状态判断是否须要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的构造,转换实现后将通过表达式引擎解析表达式并获得正确的值,通过事件解析引擎解析用户自定义事件并实现事件的绑定,实现解析赋值以及事件绑定后进行视图的渲染,最终将指标页面展现到屏幕。
5.1 询价接单接口革新
如源代码构造,依据不同业务起源,写在一个办法里通过 if…else… 别离组装场景,一旦上游任一零碎存在需要变动,以后接单接口调用逻辑须要变动:
【python】def receive_enquiry_bill(**kwargs):
params=[{}]
params[0].update(kwargs)
if params[0].get("enquirySource") == 8:
pass
elif params[0].get("enquiryWay") == 2 and params[0].get("payMode") == 2:pass
elif params[0].get("enquiryWay") == 2 and params[0].get("payMode") == 3:pass
if params[0].get("enquirySource") == 46:
pass
if params[0].get("enquirySource") == 20:
pass
革新构造:
上下文类
【python】class AlgorithmStrategy(object):
def __init__(self, algorithm_name):
self.algorithm_name = algorithm_name
@property
def algorithm(self):
return self.algorithm_name
@algorithm.setter
def algorithm(self, name): self.algorithm_name = name
def execute_algorithm(self, params): return self.algorithm_name.execute(params)
算法基类
【python】class CreateEnquiryBillBaseAlgorithm(ABC):# 算法能力基类
@abstractmethod
def read_params(self,
**kwargs):
scenario=kwargs['scenario'] if "scenario" in kwargs and kwargs['scenario'] else【python】def receive_enquiry_bill(**kwargs):
params=[{}]
params[0].update(kwargs)
if params[0].get("enquirySource") == 8:
pass
elif params[0].get("enquiryWay") == 2 and params[0].get("payMode") == 2:
pass
elif params[0].get("enquiryWay") == 2 and params[0].get("payMode") == 3:
pass
if params[0].get("enquirySource") == 46:
pass
if params[0].get("enquirySource") == 20:
pass'base' return resource_custom_data[self.__class__.__name__][scenario][0].update(kwargs)
@abstractmethod def execute(self, params): return jsf_receive_enquiry_bill(data=json.dumps(params)
不同算法:
【python】class CreateTFCEnquiryBill(CreateEnquiryBillBaseAlgorithm): def read_params(self, **kwargs):
params = super().read_params(**kwargs) params[0].update({"businessCode": kwargs['businessCode'] if 'businessCode' in kwargs else f"TJ{laputa_util.date_time_str(fmt='%y%m%d')}{laputa_util.get_random_num(8)}","receiveBeginTime": tms_util.data_time_str(minutes=100),"deliveryBeginTime": tms_util.data_time_str(minutes=180)})
return params
def execute(self, params):
return super().execute(params)
class CreateECLPClodEnquiryBill(CreateEnquiryBillBaseAlgorithm):
def read_params(self, **kwargs):
# 若以后场景参数与根底参数改变较大倡议间接在 Yaml 里另写 Key
params=super().read_params(**kwargs)
params[0].update({"businessCode": kwargs['businessCode'] if 'businessCode' in kwargs else f"ECO{laputa_util.date_time_str(fmt='%y%m%d')}{laputa_util.get_random_num(8)}","receiveBeginTime": tms_util.data_time_str(minutes=100),"deliveryBeginTime": tms_util.data_time_str(minutes=180)})return params
def execute(self, params):
super().execute(params)return jsf_do_assign(data=json.dumps(params))
算法注入应用:
【python】def receive_enquiry_bill(algOne=None, sceOne=None, **kwargs):
"""
Args:
algorithm: 业务类型
scenario: 测试场景:执行步骤,执行数据
Returns:
"""
if algorithm:
# 采纳字典模式进行手动注册算法,由 python 动静查找
st = {"TFC": CreateTFCEnquiryBill(), "ECLP 冷链": CreateECLPClod
EnquiryBill(), "TC": CreateTCEnquiryBill(),"终端用车": CreateTerminalEnquiryBill()}
query_algorithm = st.get(algOne)
return
query_algorithm.execute(query_algorithm.read_params(scenario=sceOne, **kwargs))
else:
pass
当有需要变动,只需批改其一策略规定外部代码,如【分单策略需要】,除运输外部零碎 TFC 下发询价指定个体标签,其余上游没有减少标签下发性能,则只需批改 CreateTFCEnquiryBill()代码即可。
5.2 Common 用例组装
拼接 task 客户端办法组成 case,利用 feature 组装测试数据,数据驱动测试方法执行。
【python】@pytest.mark.parametrize("params", test_data('test_enquiry_core'), indirect=True)def test_enquiry_core(params):
enquiry_code = receive_enquiry_bill_core(**params).get("data")
return quote_enquiry_bill_core(enquiry_code=enquiry_code, **params)
06 总结
了解,首先 MCube 会根据模板缓存状态判断是否须要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的构造,转换实现后将通过表达式引擎解析表达式并获得正确的值,通过事件解析引擎解析用户自定义事件并实现事件的绑定,实现解析赋值以及事件绑定后进行视图的渲染,最终将指标页面展现到屏幕。
随着运输八大产品建设方向逐渐明确,自动化平台须要从利用维度重构到产品维度,在脚本一直交融和解耦过程,如何在新的分层模式设计高复用性脚本,须要大家联合各自业务条线一直优化改良。