随着运输业务场景的不断丰富和自动化脚本量的不断累积,日常在review用例时发现,目前大家仍停留在针对需求定制化用例编写,无法提高用例可复用性和可编排性。当业务流程中间某一环节发生变化时,不但需要重新修改脚本,还会影响当前应用其他用例执行结果。所以,如何设计高复用性脚本成为目前自动化建设的关键节点。
2.1 设计理念
根据面向对象程序设计理念,设计者应遵循高内聚与低耦合原则,通常程序结构中各模块的内聚程度越高,模块间的耦合程度就越低。高内聚意味着一个类所能提供的功能应该是相关的,即一个类不要设计得包括很多互不相干的功能,低耦合代表要合理规划模块的颗粒度,即要保证一个模块可独立存在,降低模块之间复杂依赖关系。
2.2 策略模式
3.1 基本思路
3.2 方案分析
优点:
1. 代码解耦,便于维护;
2. 避免使用难以维护的多重条件选择语句;
3. 可以运行时动态切换算法;
4. 开闭原则。无须对上下文代码进行修改,就可以添加新的代码。
缺点:
1. 如果算法逻辑,较为固定,不经常修改,使用策略模式只会增加代码量
4.1 环境依赖
Laputa框架简介:
Laputa框架基于 Pytest 集成了对API接口自动化, 以及对 Web应用, 移动端应用和 Windows 桌面应用 UI 等自动化的能力。具有可视化的Web界面工具, 便于配置执行规则,关联执行脚本, 触发用例执行,查看执行结果。提供CI集成服务,调用Jenkins API跟踪持续集成结果,开放接口,实现流水线自动化测试。
图1 自动化框架架构图
4.2 分层改造
图2 自动化用例分层图
4.3 策略设计
4.4 操作步骤
1. 将频繁修改的算法进行抽取,独立为具体的算法类;
2. 创建抽象基类,实现一个约定的抽象策略方法;
3. 所有独立的算法类,必须实现基类中的抽象策略接口;
4. 建立上下类,该类可以动态的对算法进行setter,创建调用具体算法的方法,上下文可通过该方法与具体的策略交互;
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 '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冷链": CreateECLPClodEnquiryBill(), "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)
随着运输八大产品建设方向逐步明确,自动化平台需要从应用维度重构到产品维度,在脚本不断融合和解耦过程,如何在新的分层模式设计高复用性脚本,需要大家结合各自业务条线不断优化改进。
求分享
求点赞
求在看