在软件研发迭代越来越快的今天,手工测试的局限性日益凸显——重复劳动、效率低下、难以覆盖复杂场景。作为一名测试或开发工程师,你是否也曾在深夜为回归测试而烦恼?Python 凭借其简洁的语法和强大的生态,已成为自动化测试领域的首选语言。本文将为你呈现一套从零开始的 Python 自动化测试实战指南,内容涵盖基础概念、核心工具链(Selenium, Playwright, Pytest)的深度使用,以及一个完整的 Web 项目实战。无论你是零基础的小白,还是希望系统提升的测试工程师,都能通过本文构建起从环境搭建、脚本编写到框架设计、项目落地的完整知识体系,最终实现测试工作的自动化与智能化。
1. 自动化测试基础与 Python 环境搭建
1.1 什么是自动化测试?
自动化测试是指利用软件工具、脚本和框架来执行测试用例,替代人工操作,并对实际结果与预期结果进行比较的过程。其核心价值在于:
- 提升效率:将重复、机械的测试任务交给机器,释放人力进行更有价值的探索性测试。
- 提高覆盖率:可以快速执行海量测试用例,覆盖手工测试难以触及的边界场景。
- 保证一致性:避免人为疏忽,每次执行都严格遵循预设步骤。
- 支持持续集成/持续交付 (CI/CD):是 DevOps 流程中不可或缺的一环,确保每次代码提交的质量。
根据测试对象的不同,自动化测试主要分为:
- UI 自动化测试:模拟用户操作浏览器或应用程序界面,如 Selenium、Playwright。
- 接口自动化测试:直接调用 API 接口进行测试,不经过前端界面,如 Requests + Pytest。
- 单元测试:针对代码的最小可测试单元(函数、方法)进行测试,如 Unittest、Pytest。
1.2 为什么选择 Python?
Python 在自动化测试领域占据主导地位,原因如下:
- 语法简洁:代码可读性高,学习曲线平缓,适合测试人员快速上手。
- 生态丰富:拥有大量成熟、稳定的测试库和框架(Selenium, Pytest, Requests, Appium等)。
- 跨平台:在 Windows、macOS、Linux 上均可运行。
- 社区活跃:遇到问题容易找到解决方案和社区支持。
1.3 Python 环境搭建与 IDE 配置
工欲善其事,必先利其器。一个稳定的开发环境是成功的第一步。
步骤一:安装 Python访问 Python 官方网站下载安装包。对于自动化测试,推荐使用 Python 3.8 及以上版本,以保证对新库的良好兼容性。安装时务必勾选 “Add Python to PATH” 选项。
安装完成后,打开命令行(CMD 或 Terminal),输入以下命令验证:
python --version # 或 python3 --version应显示类似Python 3.10.6的版本信息。
步骤二:安装包管理工具 pippip 是 Python 的包安装工具,通常随 Python 一起安装。检查 pip 版本:
pip --version如果提示找不到命令,可能需要手动安装或修复 Python 环境变量。
步骤三:配置虚拟环境 (Virtual Environment)强烈建议为每个项目创建独立的虚拟环境,以避免不同项目间的依赖冲突。
# 安装虚拟环境工具(如果尚未安装) pip install virtualenv # 为你的自动化测试项目创建一个新目录并进入 mkdir python_auto_test && cd python_auto_test # 创建虚拟环境,环境文件夹名为 `venv` python -m venv venv # 激活虚拟环境 # Windows: venv\Scripts\activate # macOS/Linux: source venv/bin/activate激活后,命令行提示符前会出现(venv)标识。
步骤四:选择并配置 IDE
- VSCode:轻量、插件丰富,是当前非常流行的选择。安装 Python 和 Pytest 相关插件即可。
- PyCharm:JetBrains 出品,功能强大,对 Python 支持和测试集成非常友好,社区版免费。
本文后续示例将基于 VSCode 进行。
2. 自动化测试核心工具链详解
一个高效的自动化测试工作流,离不开一系列核心工具的支撑。下面我们介绍最主流的组合。
2.1 Selenium:Web UI 自动化的基石
Selenium 是一个用于 Web 应用程序测试的便携式框架。它支持多种浏览器(Chrome, Firefox, Edge等)和多种编程语言。
安装:在激活的虚拟环境中运行:
pip install selenium此外,你还需要下载对应浏览器的WebDriver(如chromedriver),并将其所在目录添加到系统 PATH 环境变量中,或者将驱动文件放在项目目录下。这是 Selenium 控制浏览器的桥梁。
一个最简单的 Selenium 示例:
# test_selenium_demo.py from selenium import webdriver from selenium.webdriver.common.by import By import time # 1. 创建 WebDriver 实例,启动 Chrome 浏览器 # 确保 chromedriver 在 PATH 或指定路径 driver = webdriver.Chrome() try: # 2. 打开网页 driver.get("https://www.baidu.com") time.sleep(2) # 等待页面加载,实际项目中应使用更智能的等待 # 3. 定位元素并操作 # 通过元素ID定位搜索框 search_box = driver.find_element(By.ID, "kw") search_box.send_keys("Python自动化测试") # 输入文本 # 通过元素ID定位“百度一下”按钮并点击 search_button = driver.find_element(By.ID, “su”) search_button.click() time.sleep(3) # 等待搜索结果加载 # 4. 断言验证(简单示例) assert “Python自动化测试” in driver.title print(“测试通过:页面标题包含搜索关键词”) finally: # 5. 关闭浏览器 driver.quit()关键点解析:
By.ID:是定位元素的一种策略,其他还有By.NAME,By.CLASS_NAME,By.XPATH,By.CSS_SELECTOR。time.sleep:强制等待,是一种不推荐的等待方式。在实际项目中应使用显式等待。driver.quit():关闭浏览器并释放 WebDriver 资源,必须执行。
2.2 Playwright:新一代浏览器自动化利器
Playwright 由微软开发,支持 Chromium、Firefox 和 WebKit,一个 API 即可跨浏览器工作。它比 Selenium 更现代,提供了自动等待、网络拦截、移动端模拟等强大功能。
安装:
pip install playwright # 安装浏览器(Chromium, Firefox, WebKit) playwright installPlaywright 快速示例:
# test_playwright_demo.py import asyncio from playwright.async_api import async_playwright async def main(): async with async_playwright() as p: # 启动浏览器(默认无头模式,headless=False 可看到界面) browser = await p.chromium.launch(headless=False) page = await browser.new_page() # 导航到页面,Playwright 会自动等待页面加载到“load”状态 await page.goto(“https://www.baidu.com”) # 定位并操作元素,语法更简洁 await page.fill(‘input#kw’, ‘Playwright自动化测试’) await page.click(‘input#su’) # 等待导航完成 await page.wait_for_load_state(‘networkidle’) # 获取页面标题并断言 title = await page.title() assert ‘Playwright’ in title print(f“页面标题是:{title}”) # 截图(非常方便的功能) await page.screenshot(path=‘search_result.png’) await browser.close() # 运行异步函数 asyncio.run(main())Playwright 优势:
- 自动等待:大部分操作(如
click,fill)会自动等待元素可交互,无需手动添加等待。 - 强大的选择器:支持 CSS、XPath、文本内容等多种定位方式,且语法统一。
- 多上下文与设备模拟:轻松模拟移动设备、地理位置、权限等。
- 网络拦截与 Mock:可以拦截和修改网络请求,便于测试。
2.3 Pytest:强大而灵活的测试框架
Pytest 是 Python 社区最主流的测试框架,它让编写和运行测试变得简单而有趣。
安装与基本使用:
pip install pytest编写一个简单的 Pytest 测试:
# test_calculator.py # 文件名需以 `test_` 开头或 `_test` 结尾 # 函数名需以 `test_` 开头 def add(a, b): return a + b def test_add_positive_numbers(): assert add(2, 3) == 5 def test_add_negative_numbers(): assert add(-1, -1) == -2 def test_add_with_zero(): assert add(5, 0) == 5在命令行中,进入该文件所在目录,运行:
pytest test_calculator.py -v-v参数表示输出详细信息。Pytest 会自动发现并运行所有test_开头的函数,并用绿色的.或PASSED表示测试通过。
Pytest 核心特性:
- Fixture:用于提供测试所需的数据、环境或资源,实现 setup/teardown 逻辑。
import pytest @pytest.fixture def sample_data(): data = [1, 2, 3, 4, 5] yield data # 测试函数执行前返回data,执行后执行清理(如果有) print(“测试结束,清理数据”) # 可选的清理代码 def test_data_length(sample_data): # 使用 fixture assert len(sample_data) == 5 - 参数化测试:用一组数据驱动同一个测试逻辑。
import pytest @pytest.mark.parametrize(“a,b,expected”, [ (1, 2, 3), (4, 5, 9), (10, -5, 5), ]) def test_add_param(a, b, expected): assert add(a, b) == expected - 丰富的插件生态:如
pytest-html(生成HTML报告)、pytest-xdist(并行测试)、pytest-cov(覆盖率报告)。
2.4 Requests:接口自动化测试的核心库
对于后端 API 测试,requests库是事实上的标准。
安装与简单示例:
pip install requests# test_api_demo.py import requests import pytest # 定义一个测试用的 API 端点(这里使用免费的公共API) BASE_URL = “https://jsonplaceholder.typicode.com” def test_get_posts(): response = requests.get(f“{BASE_URL}/posts/1”) # 断言状态码 assert response.status_code == 200 # 断言响应体结构 data = response.json() assert ‘id’ in data assert data[‘id’] == 1 assert ‘title’ in data print(f“获取到的文章标题:{data[‘title’]}”) def test_create_post(): new_post = { “title”: “foo”, “body”: “bar”, “userId”: 1, } headers = {‘Content-type’: ‘application/json; charset=UTF-8’} response = requests.post(f“{BASE_URL}/posts”, json=new_post, headers=headers) assert response.status_code == 201 created_data = response.json() assert created_data[‘title’] == ‘foo’ assert ‘id’ in created_data print(f“创建的文章ID:{created_data[‘id’]}”)3. 项目实战:搭建一个简易的 Web 自动化测试框架
我们将综合运用以上工具,为一个假设的在线图书商城(我们本地启动一个简易 Flask 应用来模拟)搭建一个自动化测试框架。
3.1 项目结构与需求分析
项目目标:测试一个具有登录、浏览图书、搜索功能的 Web 应用。项目结构:
bookstore_auto_test/ ├── conftest.py # Pytest 共享配置和 Fixture ├── requirements.txt # 项目依赖 ├── pages/ # 页面对象模型 (Page Object Model) │ ├── __init__.py │ ├── base_page.py │ ├── login_page.py │ └── home_page.py ├── tests/ # 测试用例 │ ├── __init__.py │ ├── test_login.py │ └── test_search.py ├── utils/ # 工具类 │ ├── __init__.py │ └── driver_manager.py └── app.py # 模拟的 Web 应用 (Flask)3.2 模拟 Web 应用 (app.py)
为了实战,我们先创建一个极简的 Flask 应用作为测试目标。
# app.py from flask import Flask, render_template_string, request, redirect, url_for, session app = Flask(__name__) app.secret_key = ‘your_secret_key_here’ # 用于 session # 模拟的图书数据 BOOKS = [ {“id”: 1, “title”: “Python编程从入门到实践”, “author”: “Eric Matthes”, “price”: 89.0}, {“id”: 2, “title”: “Selenium自动化测试指南”, “author”: “Unmesh Gundecha”, “price”: 79.0}, {“id”: 3, “title”: “玩转Playwright”, “author”: “微软”, “price”: 69.0}, {“id”: 4, “title”: “Pytest实战”, “author”: “Brian Okken”, “price”: 59.0}, ] @app.route(‘/’) def home(): user = session.get(‘username’, ‘Guest’) html = “”” <h1>欢迎来到简易图书商城,{{ user }}!</h1> <a href=“/login”>登录</a> | <a href=“/books”>查看所有图书</a> <form action=“/search” method=“get”> <input type=“text” name=“q” placeholder=“搜索图书…”> <button type=“submit”>搜索</button> </form> “”” return render_template_string(html, user=user) @app.route(‘/login’, methods=[‘GET’, ‘POST’]) def login(): if request.method == ‘POST’: username = request.form[‘username’] password = request.form[‘password’] # 简单验证:用户名为 ‘test’,密码为 ‘123456’ if username == ‘test’ and password == ‘123456’: session[‘username’] = username return redirect(url_for(‘home’)) else: return “登录失败,用户名或密码错误”, 401 # GET 请求返回登录表单 login_form = “”” <form method=“post”> 用户名:<input type=“text” name=“username”><br> 密码:<input type=“password” name=“password”><br> <button type=“submit”>登录</button> </form> “”” return login_form @app.route(‘/books’) def list_books(): book_list = “<h1>图书列表</h1><ul>” for book in BOOKS: book_list += f“<li>{book[‘title’]} - {book[‘author’]} (¥{book[‘price’]})</li>” book_list += “</ul><a href=‘/’>返回首页</a>” return book_list @app.route(‘/search’) def search(): query = request.args.get(‘q’, ‘’).lower() results = [b for b in BOOKS if query in b[‘title’].lower()] result_html = f“<h1>搜索 ‘{query}’ 的结果</h1>” if results: result_html += “<ul>” for book in results: result_html += f“<li>{book[‘title’]} - {book[‘author’]}</li>” result_html += “</ul>” else: result_html += “<p>未找到相关图书。</p>” result_html += “<a href=‘/’>返回首页</a>” return result_html if __name__ == ‘__main__’: app.run(debug=True, port=5000)运行python app.py,访问http://127.0.0.1:5000即可看到应用。
3.3 核心框架代码实现
1. 依赖文件 (requirements.txt)
selenium>=4.10.0 pytest>=7.3.1 pytest-html>=3.2.0 webdriver-manager>=3.8.6 # 自动管理浏览器驱动 Flask>=2.3.2 # 仅用于运行模拟应用,测试代码本身不依赖使用pip install -r requirements.txt安装所有依赖。webdriver-manager可以自动下载和匹配浏览器驱动,省去手动管理的麻烦。
2. 驱动管理工具 (utils/driver_manager.py)
# utils/driver_manager.py from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager from webdriver_manager.firefox import GeckoDriverManager class DriverManager: @staticmethod def get_chrome_driver(headless=False): “”“获取 Chrome WebDriver 实例”“” options = webdriver.ChromeOptions() if headless: options.add_argument(‘--headless’) # 无头模式,不打开浏览器窗口 options.add_argument(‘--no-sandbox’) options.add_argument(‘--disable-dev-shm-usage’) # 使用 webdriver-manager 自动管理驱动 service = Service(ChromeDriverManager().install()) driver = webdriver.Chrome(service=service, options=options) driver.implicitly_wait(10) # 设置隐式等待,全局生效 driver.maximize_window() return driver @staticmethod def get_firefox_driver(headless=False): “”“获取 Firefox WebDriver 实例”“” options = webdriver.FirefoxOptions() if headless: options.add_argument(‘--headless’) service = Service(GeckoDriverManager().install()) driver = webdriver.Firefox(service=service, options=options) driver.implicitly_wait(10) driver.maximize_window() return driver3. 页面对象模型 (Page Object Model, POM)POM 是一种设计模式,将页面元素定位和操作封装成类,提高代码复用性和可维护性。
基础页面类 (pages/base_page.py):
# pages/base_page.py from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC class BasePage: def __init__(self, driver): self.driver = driver self.wait = WebDriverWait(driver, 10) # 显式等待,最多10秒 def find_element(self, by, locator): “”“查找单个元素,使用显式等待”“” return self.wait.until(EC.presence_of_element_located((by, locator))) def find_elements(self, by, locator): “”“查找多个元素”“” return self.driver.find_elements(by, locator) def click(self, by, locator): “”“点击元素”“” element = self.find_element(by, locator) element.click() def input_text(self, by, locator, text): “”“向输入框输入文本”“” element = self.find_element(by, locator) element.clear() element.send_keys(text) def get_title(self): “”“获取页面标题”“” return self.driver.title登录页面类 (pages/login_page.py):
# pages/login_page.py from selenium.webdriver.common.by import By from .base_page import BasePage class LoginPage(BasePage): # 页面元素定位器 USERNAME_INPUT = (By.NAME, ‘username’) PASSWORD_INPUT = (By.NAME, ‘password’) SUBMIT_BUTTON = (By.XPATH, “//button[@type=‘submit’]”) ERROR_MESSAGE = (By.TAG_NAME, ‘body’) # 简化处理,错误信息在body中 def __init__(self, driver): super().__init__(driver) self.driver = driver def open(self, url): self.driver.get(url) def login(self, username, password): self.input_text(*self.USERNAME_INPUT, username) self.input_text(*self.PASSWORD_INPUT, password) self.click(*self.SUBMIT_BUTTON) def get_error_message(self): # 这是一个简单示例,实际中错误信息可能有特定元素 return self.find_element(*self.ERROR_MESSAGE).text首页类 (pages/home_page.py):
# pages/home_page.py from selenium.webdriver.common.by import By from .base_page import BasePage class HomePage(BasePage): SEARCH_BOX = (By.NAME, ‘q’) SEARCH_BUTTON = (By.XPATH, “//button[@type=‘submit’]”) BOOKS_LINK = (By.LINK_TEXT, ‘查看所有图书’) LOGIN_LINK = (By.LINK_TEXT, ‘登录’) GREETING_TEXT = (By.TAG_NAME, ‘h1’) def search_book(self, keyword): self.input_text(*self.SEARCH_BOX, keyword) self.click(*self.SEARCH_BUTTON) def go_to_books_page(self): self.click(*self.BOOKS_LINK) def go_to_login_page(self): self.click(*self.LINK_LINK)4. Pytest 配置与共享 Fixture (conftest.py)
# conftest.py import pytest from utils.driver_manager import DriverManager @pytest.fixture(scope=“function”) # 每个测试函数执行一次 def driver(): “”“提供 WebDriver 实例”“” driver = DriverManager.get_chrome_driver(headless=True) # 测试时用无头模式 yield driver driver.quit() # 测试结束后退出浏览器 @pytest.fixture def login_page(driver): “”“提供登录页面实例”“” from pages.login_page import LoginPage page = LoginPage(driver) page.open(“http://127.0.0.1:5000/login”) return page @pytest.fixture def home_page(driver): “”“提供首页实例”“” from pages.home_page import HomePage page = HomePage(driver) page.open(“http://127.0.0.1:5000/”) return page3.4 编写并运行测试用例
测试登录功能 (tests/test_login.py):
# tests/test_login.py import pytest class TestLogin: “”“测试登录功能”“” def test_login_success(self, login_page): “”“测试成功登录”“” login_page.login(‘test’, ‘123456’) # 登录成功后应跳转到首页,首页的欢迎语包含用户名 assert ‘test’ in login_page.driver.page_source print(“登录成功测试通过”) def test_login_failure(self, login_page): “”“测试登录失败”“” login_page.login(‘wrong’, ‘password’) error_text = login_page.get_error_message() assert ‘登录失败’ in error_text or ‘401’ in error_text print(“登录失败测试通过”)测试搜索功能 (tests/test_search.py):
# tests/test_search.py import pytest class TestSearch: “”“测试搜索功能”“” def test_search_existing_book(self, home_page): “”“搜索存在的图书”“” home_page.search_book(‘Python’) assert ‘Python编程从入门到实践’ in home_page.driver.page_source print(“搜索存在的图书测试通过”) def test_search_non_existing_book(self, home_page): “”“搜索不存在的图书”“” home_page.search_book(‘不存在的书’) assert ‘未找到相关图书’ in home_page.driver.page_source print(“搜索不存在的图书测试通过”)运行测试并生成报告:在项目根目录下执行以下命令:
# 1. 首先确保模拟应用在运行 (在另一个终端运行 `python app.py`) # 2. 运行所有测试 pytest tests/ -v # 3. 运行测试并生成HTML报告 pytest tests/ -v --html=report.html --self-contained-html # 4. 只运行某个文件 pytest tests/test_login.py -v # 5. 运行带有特定标记的测试(需先使用 @pytest.mark.xxx 装饰器标记) # pytest tests/ -m “login” -v运行后,会生成一个report.html文件,用浏览器打开即可查看详细的测试结果、通过率、失败原因和日志,非常适合集成到 CI/CD 流程中。
4. 常见问题与排查思路
在自动化测试实践中,你会遇到各种各样的问题。下面是一些典型问题及其解决方案。
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
WebDriverException: Message: ‘chromedriver’ executable needs to be in PATH | 1. 未安装 ChromeDriver。 2. ChromeDriver 版本与 Chrome 浏览器版本不匹配。 3. ChromeDriver 路径未加入系统环境变量。 | 1.最佳方案:使用webdriver-manager自动管理驱动(如本文示例)。2. 手动下载:访问 ChromeDriver 官网,下载与本地 Chrome 浏览器大版本号一致的驱动。 3. 将驱动文件放在项目目录下,并在代码中指定路径: webdriver.Chrome(executable_path=‘./chromedriver’)。 |
NoSuchElementException或元素找不到 | 1. 页面未加载完成就进行元素定位。 2. 元素定位器(如ID、XPath)写错了。 3. 元素在 iframe 或 Shadow DOM 内。 4. 页面是动态生成的,元素属性会变。 | 1.使用智能等待:用WebDriverWait配合expected_conditions(如presence_of_element_located,element_to_be_clickable)。2.检查定位器:使用浏览器开发者工具(F12)的 Console 验证: $x(‘your_xpath’)或$(‘your_css’)。3.处理 iframe:先用 driver.switch_to.frame(frame_element)切换到 iframe。4.使用更稳定的定位器:优先使用 id,name, 稳定的css selector,避免使用绝对 XPath。 |
| 测试在无头模式下通过,但有界面时失败 | 1. 界面加载速度差异导致时机问题。 2. 浏览器窗口大小影响元素可见性或布局。 | 1. 增加等待时间或使用更可靠的等待条件。 2. 在有界面模式下也使用 driver.maximize_window()确保一致性。3. 检查是否有弹窗、通知遮挡了元素。 |
| Pytest 找不到测试用例 | 1. 测试文件或函数命名不符合 Pytest 发现规则。 2. 未在正确的目录下运行 pytest。 | 1. 确保测试文件以test_开头或_test结尾(如test_login.py)。2. 确保测试函数以 test_开头。3. 在项目根目录或包含 tests目录的上级目录运行pytest。 |
测试报告report.html为空或样式丢失 | 使用--html=report.html时未添加--self-contained-html参数。 | 使用命令pytest --html=report.html --self-contained-html。--self-contained-html会将 CSS 和 JS 内嵌到 HTML 中,使报告可独立查看。 |
| 接口测试返回 4xx/5xx 错误 | 1. 请求头(如Content-Type,Authorization)缺失或错误。2. 请求参数格式错误。 3. 接口地址或方法(GET/POST)错误。 4. 需要处理 cookies 或 session。 | 1. 使用抓包工具(如浏览器F12的Network面板)查看成功请求的详细信息,并模仿其请求头和参数。 2. 对于 JSON 数据,使用 requests.post(url, json=data)而非data=data。3. 使用 session = requests.Session()来保持会话状态。 |
5. 最佳实践与工程建议
掌握了基础工具和框架后,要写出健壮、可维护的自动化测试代码,还需要遵循以下最佳实践。
5.1 测试代码设计原则
- 单一职责:每个测试用例只验证一个功能点。一个失败的测试能清晰指出问题所在。
- 独立性:测试用例之间不应该有依赖。使用 Fixture 的
setup/teardown确保每个测试都在干净的环境中开始。 - 可读性:给测试用例和函数起一个描述性的名字(如
test_login_with_invalid_password_should_fail)。在断言失败时,信息应清晰明了。 - 稳定性:避免使用
time.sleep()进行固定等待。务必使用隐式等待 (implicitly_wait) 和显式等待 (WebDriverWait)。 - 可维护性:积极采用页面对象模型 (POM)。当页面 UI 变更时,你只需要修改对应的 Page 类中的定位器,而不需要修改大量测试用例。
5.2 数据驱动测试
将测试数据与测试逻辑分离。Pytest 的@pytest.mark.parametrize是绝佳工具。
import pytest login_test_data = [ (‘test’, ‘123456’, True, ‘登录成功’), (‘wrong’, ‘123456’, False, ‘用户名错误’), (‘test’, ‘wrong’, False, ‘密码错误’), (‘’, ‘’, False, ‘用户名密码为空’), ] @pytest.mark.parametrize(“username, password, expected_success, description”, login_test_data) def test_login_ddt(login_page, username, password, expected_success, description): login_page.login(username, password) if expected_success: assert ‘test’ in login_page.driver.page_source else: assert ‘登录失败’ in login_page.driver.page_source or ‘401’ in login_page.driver.page_source print(f“测试用例 ‘{description}’ 通过”)5.3 配置管理与环境隔离
- 使用配置文件:将 URL、用户名、密码、超时时间等配置信息放在配置文件(如
config.yaml或config.ini)或环境变量中,不要硬编码在代码里。 - 区分环境:为开发、测试、生产环境准备不同的配置文件。
- 使用
.gitignore:确保配置文件(尤其是包含密码的)不被提交到版本库。
5.4 日志与报告
- 记录详细日志:使用 Python 的
logging模块记录测试执行的关键步骤和错误信息,便于排查。 - 丰富的测试报告:除了
pytest-html,还可以结合allure-pytest生成更美观、交互性更强的 Allure 报告。 - 失败截图:在测试失败时自动截图,能极大帮助定位 UI 问题。可以在 Pytest 的
conftest.py中通过 hook 函数实现。# conftest.py 中添加 import pytest from datetime import datetime @pytest.hookimpl(hookwrapper=True) def pytest_runtest_makereport(item, call): outcome = yield report = outcome.get_result() if report.when == “call” and report.failed: # 假设 driver 是 fixture if ‘driver’ in item.fixturenames: driver = item.funcargs[‘driver’] timestamp = datetime.now().strftime(“%Y%m%d_%H%M%S”) screenshot_path = f“./screenshots/failure_{item.name}_{timestamp}.png” driver.save_screenshot(screenshot_path) print(f“Screenshot saved to: {screenshot_path}”)
5.5 集成到 CI/CD 流水线
自动化测试的真正价值在于持续集成。你可以将测试套件集成到 Jenkins、GitLab CI、GitHub Actions 等工具中。
- GitHub Actions 示例:在项目根目录创建
.github/workflows/test.yml。name: Python Automated Tests on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: python-version: ‘3.10’ - name: Install dependencies run: | pip install -r requirements.txt playwright install chromium - name: Run Flask app in background run: | python app.py & sleep 5 # 等待应用启动 - name: Run tests with pytest run: | pytest tests/ -v --html=report.html --self-contained-html - name: Upload test report uses: actions/upload-artifact@v3 if: always() with: name: test-report path: report.html
6. 总结与进阶学习路线
通过本文,你已经完成了从零到一的 Python 自动化测试入门,掌握了环境搭建、Selenium/Playwright 操作、Pytest 框架使用、页面对象模型设计以及一个完整项目的实战。这为你打下了坚实的基础。
下一步,你可以沿着以下方向深入:
- 深入 Playwright:学习其高级特性,如网络拦截、下载/上传处理、跨浏览器测试、移动端模拟、录制生成代码等。
- 接口自动化测试进阶:学习使用
pytest+requests+Allure搭建更专业的接口测试框架,处理 Token 认证、数据加密、数据库断言等。 - 移动端自动化:学习
Appium框架,进行 Android/iOS 原生应用或混合应用的自动化测试。 - 测试框架设计:思考如何设计数据驱动、关键字驱动、行为驱动(如
behave)的测试框架,以适应更复杂的业务。 - 持续集成/持续部署 (CI/CD):将你的自动化测试脚本无缝集成到团队的 DevOps 流程中,实现代码提交即触发测试。
- AI 在测试中的应用:探索如何利用 AI 进行视觉测试、测试用例生成、缺陷预测等,这是当前的前沿方向。
自动化测试是一个需要不断实践和总结的领域。从模仿本文的示例开始,尝试为你正在参与的项目添加自动化测试,从小模块做起,逐步构建起守护产品质量的自动化防线。记住,好的测试代码和生产代码同等重要。