基于Appium与Pytest的Excel数据驱动自动化测试实现
使用OpenPyXL处理Excel测试数据
在Python中,openpyxl是处理.xlsx格式文件的常用库,支持读写操作。测试用例需存储在.xlsx文件中(不支持由.xls转换的文件)。
# excel_handler.py
from openpyxl import load_workbook
class ExcelManager:
def __init__(self, file_path, sheet=None):
self.file_path = file_path
self.sheet_name = sheet
def fetch_all_cases(self):
workbook = load_workbook(self.file_path)
worksheet = workbook.active if not self.sheet_name else workbook[self.sheet_name]
headers = tuple(worksheet.iter_rows(max_row=1, values_only=True))[0]
test_data = []
for row in worksheet.iter_rows(min_row=2, values_only=True):
test_data.append(dict(zip(headers, row)))
return test_data
def write_test_result(self, row_num, actual_result, status):
workbook = load_workbook(self.file_path)
worksheet = workbook.active if not self.sheet_name else workbook[self.sheet_name]
if isinstance(row_num, int) and row_num >= 2:
worksheet.cell(row=row_num, column=6).value = actual_result
worksheet.cell(row=row_num, column=7).value = status
workbook.save(self.file_path)
Appium驱动配置与单例模式
为确保整个测试周期仅启动一个Appium会话,采用单例模式管理WebDriver实例。
# driver_manager.py
from appium import webdriver
import yaml
import os
class SingletonDriver:
_instance = None
def __new__(cls):
if cls._instance is None:
config_path = os.path.join(os.getcwd(), "config", "desired_caps.yaml")
with open(config_path, 'r', encoding='utf-8') as f:
caps = yaml.safe_load(f)["capabilities"]
cls._instance = super().__new__(cls)
cls._instance.driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", caps)
return cls._instance
def get_webdriver(self):
return self.driver
动态执行测试步骤
通过反射机制解析Excel中的操作指令并动态调用对应方法。利用自定义上下文类保存页面元素引用。
# step_executor.py
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.remote.webelement import WebElement
import allure
class TestContext:
pass
def execute_test_flow(excel_file, sheet_name):
driver = SingletonDriver().get_webdriver()
cases = ExcelManager(excel_file, sheet_name).fetch_all_cases()
for case in cases:
operation = case.get("action")
description = case.get("description")
element_action = case.get("find")
locator_type = case.get("selector")
locator_value = case.get("selector_value")
store_name = case.get("save_object")
target_obj = case.get("operate_object")
input_content = case.get("inputtext")
attr_name = case.get("attribute_value")
if operation == "describe":
allure.dynamic.title(description)
elif operation == "locate":
if not locator_type or not locator_value:
raise ValueError("定位类型或值缺失")
located_element = getattr(driver, element_action)(
getattr(AppiumBy, locator_type), locator_value
)
setattr(TestContext, store_name, located_element)
elif operation == "tap":
element = getattr(TestContext, target_obj)
element.click()
elif operation == "type":
element = getattr(TestContext, target_obj)
element.send_keys(input_content)
elif operation == "fetch_attr":
source_element = getattr(TestContext, target_obj)
if isinstance(source_element, WebElement):
result = source_element.get_attribute(attr_name)
else:
result = [elem.get_attribute(attr_name) for elem in source_element]
setattr(TestContext, store_name, result)
Pytest集成与参数化运行
结合Pytest框架实现测试用例参数化执行,并生成Allure报告。
# test_runner.py
import pytest
import allure
from step_executor import execute_test_flow
from excel_handler import ExcelManager
import yaml
config_data = yaml.safe_load(open("config/test_config.yaml", encoding="utf-8"))
target_cases = ExcelManager(
config_data["case_file"],
config_data["suite_sheet"]
).fetch_all_cases()
case_names = [case["用例名称"] for case in target_cases if case["是否运行"] == "y"]
@allure.epic("移动端功能验证")
class TestSuite:
@pytest.mark.parametrize("case_name", case_names)
def test_execution(self, case_name):
execute_test_flow(config_data["case_file"], case_name)
allure.dynamic.story(case_name)
执行脚本与报告生成
通过主控脚本启动测试并生成可视化报告。
# runner.py
import pytest
import os
if __name__ == "__main__":
pytest.main(["-v", "--capture=sys", "--alluredir=report/result"])
os.system("allure generate report/result -o report/html --clean")