高复用性自动化脚本设计实践
字数 1300 2025-08-11 17:40:26
高复用性自动化脚本设计实践:策略模式在自动化测试中的应用
1. 背景与痛点
在自动化测试实践中,随着业务场景的不断丰富和脚本量的累积,传统定制化用例编写方式暴露出以下问题:
- 复用性差:针对特定需求编写的用例难以复用
- 维护成本高:业务流程变化时需要大量修改脚本
- 影响范围广:修改可能影响其他用例执行结果
- 代码冗余:大量使用if...elif...else分支语句导致代码臃肿
2. 设计理念与原则
2.1 面向对象设计原则
- 高内聚:一个类提供的功能应该是相关的,避免包含不相干的功能
- 低耦合:合理规划模块颗粒度,降低模块间复杂依赖关系
2.2 策略模式简介
策略模式定义了一系列算法,将每组相关算法封装为独立策略分支,使它们可以相互替换。策略模式的特点:
- 隐藏分支相关代码
- 算法变化不影响使用算法的客户端
- 提高程序可扩展性
3. 解决方案分析
3.1 基本思路
针对运输业务中同一流程存在不同场景的情况(如询价服务接上游下发询价单节点),采用策略模式:
- 将频繁修改的算法抽取为独立算法类
- 创建抽象基类定义统一接口
- 所有算法类实现基类接口
- 建立上下文类动态管理算法
- 客户端调用时传入具体算法类
3.2 方案优缺点
优点:
- 代码解耦,便于维护
- 避免难以维护的多重条件选择语句
- 可运行时动态切换算法
- 符合开闭原则(无需修改上下文即可添加新算法)
缺点:
- 对于固定不变的算法逻辑,会增加代码量
- 需要了解所有具体策略类及其区别
4. 技术实现细节
4.1 环境依赖
使用Laputa框架,基于Pytest集成以下能力:
- API接口自动化
- Web应用UI自动化
- 移动端应用UI自动化
- Windows桌面应用UI自动化
框架特点:
- 可视化Web界面工具
- CI集成服务(Jenkins API)
- 流水线自动化测试支持
4.2 分层改造
自动化用例分层结构:
- 测试层:用例组装与执行
- 业务层:业务流程封装
- 策略层:算法策略实现
- 基础层:框架核心功能
4.3 策略模式设计
核心组件:
- 上下文类(AlgorithmStrategy):管理算法执行
- 抽象基类(CreateEnquiryBillBaseAlgorithm):定义统一接口
- 具体策略类:实现特定算法逻辑
4.4 操作步骤
- 抽取频繁修改的算法为独立类
- 创建抽象基类定义策略方法
- 具体算法类实现基类接口
- 建立上下文类管理算法
- 客户端调用时传入具体算法
5. 实践案例:询价接单接口改造
5.1 改造前代码问题
原始代码使用多重if-else分支:
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
5.2 策略模式实现
上下文类:
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)
抽象基类:
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))
具体策略类示例:
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)
客户端调用:
def receive_enquiry_bill(algOne=None, sceOne=None, **kwargs):
if algorithm:
# 手动注册算法字典
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
5.3 用例组装
使用pytest进行数据驱动测试:
@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)
6. 总结与最佳实践
- 业务维度思考:从应用维度转向产品维度设计自动化脚本
- 持续优化:随着业务发展不断优化分层模式
- 适度使用:对于频繁变化的算法逻辑才使用策略模式
- 统一管理:通过上下文类集中管理策略执行
- 开闭原则:新算法添加不影响现有代码
通过策略模式改造,实现了:
- 脚本高度复用
- 维护成本降低
- 业务变化影响局部化
- 代码结构清晰可读