自动化测试框架设计之道 – 分层架构与数据驱动最佳实践

---

前言

大家好,我是测试架构师。从业8年,搭建过多个自动化测试框架。很多测试同行问我:"框架该怎么设计?"今天这篇文章,我想系统分享自动化测试框架的设计理念和实践经验。 ---

一、为什么需要测试框架?

没有框架的痛点

直接写测试脚本的问题:

框架的价值

好的测试框架带来: ---

二、分层架构设计

三层架构模型

经典的自动化测试框架分层: ` ┌─────────────────────────────────────┐ │ 测试用例层 (Cases) │ 业务测试逻辑 ├─────────────────────────────────────┤ │ 业务逻辑层 (Services) │ 业务操作封装 ├─────────────────────────────────────┤ │ 页面对象层 (Pages) │ 元素定位、操作 ├─────────────────────────────────────┤ │ 基础设施层 (Core) │ Driver、配置、工具 └─────────────────────────────────────┘ `

各层职责

基础设施层(Core): 页面对象层(Pages): 业务逻辑层(Services): 测试用例层(Cases): ---

三、框架目录结构

Python项目结构

` test_framework/ ├── config/ # 配置文件 │ ├── config.yaml # 主配置 │ ├── dev.yaml # 开发环境 │ └── prod.yaml # 生产环境 ├── core/ # 基础设施层 │ ├── driver.py # Driver管理 │ ├── config_loader.py # 配置加载 │ ├── logger.py # 日志模块 │ ├── report.py # 报告生成 │ └── utils.py # 工具函数 ├── pages/ # 页面对象层 │ ├── base_page.py # 页面基类 │ ├── login_page.py # 登录页面 │ ├── home_page.py # 首页 │ └── order_page.py # 订单页面 ├── services/ # 业务逻辑层 │ ├── user_service.py # 用户业务 │ ├── order_service.py # 订单业务 │ └── auth_service.py # 认证业务 ├── tests/ # 测试用例层 │ ├── test_login.py # 登录测试 │ ├── test_order.py # 订单测试 │ └── conftest.py # Pytest配置 ├── data/ # 测试数据 │ ├── users.yaml # 用户数据 │ ├── orders.yaml # 订单数据 │ └── test_cases.csv # 测试数据集 ├── reports/ # 测试报告 ├── logs/ # 日志文件 ├── requirements.txt # 依赖 └── pytest.ini # Pytest配置 ` ---

四、核心模块实现

Driver管理

`python

core/driver.py

from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager from core.config_loader import Config class DriverManager: """WebDriver管理类""" _instance = None _driver = None def __new__(cls): if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance def get_driver(self): """获取Driver实例""" if self._driver is None: self._driver = self._create_driver() return self._driver def _create_driver(self): """创建Driver""" config = Config().get("browser") options = webdriver.ChromeOptions() if config.get("headless"): options.add_argument("--headless") options.add_argument("--no-sandbox") options.add_argument("--disable-dev-shm-usage") driver = webdriver.Chrome( service=Service(ChromeDriverManager().install()), options=options ) driver.maximize_window() return driver def quit_driver(self): """关闭Driver""" if self._driver: self._driver.quit() self._driver = None `

页面基类

`python

pages/base_page.py

from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from core.driver import DriverManager from core.logger import Logger class BasePage: """页面基类""" def __init__(self): self.driver = DriverManager().get_driver() self.logger = Logger() self.wait = WebDriverWait(self.driver, 10) def find_element(self, locator): """定位元素""" self.logger.info(f"定位元素: {locator}") return self.wait.until(EC.presence_of_element_located(locator)) def click(self, locator): """点击元素""" element = self.find_element(locator) self.logger.info(f"点击元素: {locator}") element.click() def input_text(self, locator, text): """输入文本""" element = self.find_element(locator) self.logger.info(f"输入文本: {text}") element.clear() element.send_keys(text) def get_text(self, locator): """获取文本""" element = self.find_element(locator) return element.text def is_visible(self, locator): """判断元素可见""" try: self.wait.until(EC.visibility_of_element_located(locator)) return True except: return False `

业务服务类

`python

services/auth_service.py

from pages.login_page import LoginPage from pages.home_page import HomePage from core.logger import Logger class AuthService: """认证业务服务""" def __init__(self): self.login_page = LoginPage() self.home_page = HomePage() self.logger = Logger() def login(self, username, password): """登录流程""" self.logger.info(f"登录: {username}") self.login_page.open() self.login_page.input_username(username) self.login_page.input_password(password) self.login_page.click_login() return self.home_page.is_logged_in() def logout(self): """退出登录""" self.logger.info("退出登录") self.home_page.click_logout() ` ---

五、数据驱动设计

数据源类型

框架支持多种数据源: | 数据源 | 格式 | 用途 | |--------|------|------| | YAML | 配置数据 | 环境配置、测试参数 | | CSV | 表格数据 | 批量测试数据 | | JSON | 结构化数据 | 复杂测试数据 | | Excel | 表格数据 | 业务数据 |

YAML数据管理

`yaml

data/users.yaml

users: valid_user: username: "testuser" password: "password123" expected: "success" invalid_user: username: "wronguser" password: "wrongpass" expected: "failure" empty_user: username: "" password: "" expected: "validation_error" `

CSV数据驱动

`python

tests/test_login.py

import pytest import csv def load_test_data(): """加载CSV测试数据""" with open("data/test_cases.csv", "r") as f: reader = csv.DictReader(f) return list(reader) @pytest.mark.parametrize("data", load_test_data()) def test_login(data): """数据驱动登录测试""" service = AuthService() result = service.login(data["username"], data["password"]) assert result == (data["expected"] == "success") ` ---

六、配置管理

配置文件设计

`yaml

config/config.yaml

browser: name: chrome headless: false window_size: maximize test: timeout: 10 retry: 3 screenshot_on_fail: true report: format: allure output_dir: reports/ environment: base_url: http://test.example.com api_url: http://api.test.example.com `

配置加载器

`python

core/config_loader.py

import yaml from pathlib import Path class Config: """配置管理""" _instance = None _config = None def __new__(cls): if cls._instance is None: cls._instance = super().__new__(cls) cls._instance._load_config() return cls._instance def _load_config(self): """加载配置""" config_path = Path("config/config.yaml") with open(config_path, "r") as f: self._config = yaml.safe_load(f) def get(self, key, default=None): """获取配置""" keys = key.split(".") value = self._config for k in keys: if isinstance(value, dict): value = value.get(k) else: return default return value if value else default ` ---

七、日志与报告

日志模块

`python

core/logger.py

import logging from datetime import datetime class Logger: """日志管理""" def __init__(self, name="test"): self.logger = logging.getLogger(name) self.logger.setLevel(logging.DEBUG) # 文件Handler file_handler = logging.FileHandler( f"logs/test_{datetime.now().strftime('%Y%m%d')}.log" ) file_handler.setLevel(logging.DEBUG) # 控制台Handler console_handler = logging.StreamHandler() console_handler.setLevel(logging.INFO) # 格式化 formatter = logging.Formatter( "%(asctime)s - %(name)s - %(levelname)s - %(message)s" ) file_handler.setFormatter(formatter) console_handler.setFormatter(formatter) self.logger.addHandler(file_handler) self.logger.addHandler(console_handler) def info(self, msg): self.logger.info(msg) def error(self, msg): self.logger.error(msg) def debug(self, msg): self.logger.debug(msg) ` ---

八、框架最佳实践

单例模式应用

Driver、Config、Logger使用单例模式,避免重复创建。

Page Object原则

业务逻辑封装

测试用例规范

---

总结

自动化测试框架设计要点: | 要点 | 内容 | |------|------| | 分层架构 | Cases -> Services -> Pages -> Core | | Driver管理 | 单例模式、自动初始化 | | Page Object | 元素定位、操作封装 | | 数据驱动 | YAML/CSV/JSON数据源 | | 配置管理 | 环境隔离、参数配置 | | 日志报告 | 日志记录、报告生成 | --- 下期预告:Jenkins测试流水线搭建 - CI/CD中的自动化测试集成实战
分享到:

探索 RunnerGo 全栈测试平台

RunnerGo 是一款面向企业的全栈测试平台,集接口测试、自动化测试、性能测试、UI测试于一体,助力企业提升研发效能。

接口测试
性能测试
自动化测试
UI测试
免费体验 RunnerGo