自动化测试框架设计
📌 自动化测试框架设计
该框架基于 pytest
,支持 Web + API 自动化测试,采用 关键字驱动,支持 远程执行、多机调度、失败重试、数据驱动(CSV),并结合 allure
生成可视化测试报告。
📂 目录结构
automation_framework/
│── config/ # 配置文件存放目录
│ ├── settings.ini # 全局配置(浏览器、API、环境等)
│ ├── remote_hosts.ini # 远程执行机列表
│
│── tests/ # 测试用例目录
│ ├── web/ # Web 相关测试
│ │ ├── test_login.py # Web登录测试
│ ├── api/ # API 相关测试
│ │ ├── test_api.py # API测试示例
│ ├── conftest.py # pytest 配置
│
│── core/ # 关键字封装
│ ├── web_keywords.py # Web自动化关键字库
│ ├── api_keywords.py # API自动化关键字库
│
│── utils/ # 工具类
│ ├── logger.py # 日志封装
│ ├── remote_executor.py # 远程执行
│ ├── screenshot.py # 截图工具
│ ├── csv_parser.py # CSV数据驱动解析
│
│── reports/ # 测试报告存放目录
│
│── logs/ # 日志存放目录
│
│── requirements.txt # 依赖包
│── run_tests.py # 运行测试主入口
│── pytest.ini # pytest 配置
│── README.md # 说明文档
📌 1. 依赖管理
requirements.txt
pytest
pytest-rerunfailures
pytest-xdist
selenium
requests
allure-pytest
paramiko
pandas
📌 2. 配置文件
config/settings.ini
[WEB]
browser = chrome
base_url = http://example.com
headless = false
implicit_wait = 5
[API]
base_url = http://example.com/api
timeout = 10
config/remote_hosts.ini
[executor_1]
host = 192.168.1.101
username = user
password = pass
[executor_2]
host = 192.168.1.102
username = user
password = pass
📌 3. Web 关键字封装
core/web_keywords.py
from selenium import webdriver
from selenium.webdriver.common.by import By
import configparser
import allure
class WebKeywords:
def __init__(self):
"""初始化浏览器驱动"""
config = configparser.ConfigParser()
config.read("config/settings.ini")
options = webdriver.ChromeOptions()
if config.getboolean("WEB", "headless"):
options.add_argument("--headless")
self.driver = webdriver.Chrome(options=options)
self.driver.implicitly_wait(config.getint("WEB", "implicit_wait"))
def open_url(self, url):
"""打开指定URL"""
self.driver.get(url)
def find_element(self, locator):
"""查找元素"""
return self.driver.find_element(By.XPATH, locator)
def click(self, locator):
"""点击元素"""
self.find_element(locator).click()
def send_keys(self, locator, text):
"""输入文本"""
self.find_element(locator).send_keys(text)
def take_screenshot(self, name):
"""截图并附加到Allure报告"""
path = f"reports/screenshots/{name}.png"
self.driver.save_screenshot(path)
allure.attach.file(path, name="screenshot", attachment_type=allure.attachment_type.PNG)
def close(self):
"""关闭浏览器"""
self.driver.quit()
📌 4. API 关键字封装
core/api_keywords.py
import requests
import configparser
class APIKeywords:
def __init__(self):
"""初始化API测试类"""
config = configparser.ConfigParser()
config.read("config/settings.ini")
self.base_url = config["API"]["base_url"]
self.timeout = config.getint("API", "timeout")
def get(self, endpoint, params=None, headers=None):
"""发送GET请求"""
return requests.get(f"{self.base_url}{endpoint}", params=params, headers=headers, timeout=self.timeout)
def post(self, endpoint, data=None, json=None, headers=None):
"""发送POST请求"""
return requests.post(f"{self.base_url}{endpoint}", data=data, json=json, headers=headers, timeout=self.timeout)
📌 5. conftest.py
配置
import pytest
import allure
from core.web_keywords import WebKeywords
from core.api_keywords import APIKeywords
@pytest.fixture(scope="session")
def web():
"""Web自动化前后置"""
web = WebKeywords()
yield web
web.close()
@pytest.fixture(scope="session")
def api():
"""API自动化前后置"""
return APIKeywords()
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item):
"""失败截图"""
outcome = yield
report = outcome.get_result()
if report.when == "call" and report.failed:
web_fixture = item.funcargs.get("web", None)
if web_fixture:
web_fixture.take_screenshot(item.name)
📌 6. CSV 数据驱动
utils/csv_parser.py
import pandas as pd
def parse_csv(file_path):
"""解析CSV文件"""
return pd.read_csv(file_path).to_dict(orient="records")
CSV 用例格式
test_name,username,password,expected
valid_login,user1,pass123,success
invalid_login,user1,wrongpass,failure
📌 7. Web 测试用例
tests/web/test_login.py
import allure
import pytest
from utils.csv_parser import parse_csv
data = parse_csv("data/login_cases.csv")
@allure.feature("Login Page")
@pytest.mark.parametrize("test_name,username,password,expected", data)
def test_login(web, test_name, username, password, expected):
web.open_url("http://example.com/login")
web.send_keys("//input[@id='username']", username)
web.send_keys("//input[@id='password']", password)
web.click("//button[@id='login']")
assert expected in web.driver.page_source
📌 8. API 测试用例
tests/api/test_api.py
import allure
@allure.feature("API Test")
def test_get_api(api):
response = api.get("/users")
assert response.status_code == 200
@allure.feature("API Test")
def test_post_api(api):
response = api.post("/login", json={"username": "test", "password": "test123"})
assert response.status_code == 200
📌 9. 远程执行
utils/remote_executor.py
import paramiko
import configparser
class RemoteExecutor:
def __init__(self):
self.config = configparser.ConfigParser()
self.config.read("config/remote_hosts.ini")
def run_remote_tests(self):
for section in self.config.sections():
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(self.config[section]["host"], username=self.config[section]["username"], password=self.config[section]["password"])
stdin, stdout, stderr = ssh.exec_command("pytest --alluredir=reports/allure-results")
print(stdout.read().decode())
ssh.close()
📌 10. 运行测试
# 本地执行
pytest --alluredir=reports/allure-results --reruns 2
# 远程执行
python utils/remote_executor.py
# 生成 Allure 报告
allure generate reports/allure-results -o reports/html-reports --clean
allure open reports/html-reports
这样,你就有了 Web + API 关键字驱动自动化框架,支持 失败重试、数据驱动、远程执行! 🚀