Python 自动化测试终极指南 (从入门到实战)
目录
- 为什么要学习 Python 自动化测试?
- 自动化测试基础
- Python 测试环境搭建
- 核心库与工具详解
- 1
unittest- Python 内置的单元测试框架 - 2
pytest- 功能强大且流行的测试框架 - 3
Selenium- Web 自动化测试利器 - 4
Requests- API 接口测试神器 - 5
Appium- 移动应用自动化测试
- 1
- 实战项目:构建一个 Web UI 自动化测试框架
- 实战项目:构建一个 API 自动化测试框架
- 高级主题与最佳实践
- 1 测试报告 (Allure, HTMLTestRunner)
- 2 持续集成 (CI/CD)
- 3 Page Object Model (POM) 设计模式
- 4 参数化与数据驱动
- 5 Mock 与 Stub (模拟依赖)
- 学习资源与社区
- 总结与学习路径建议
为什么要学习 Python 自动化测试?
在开始之前,先明确我们为什么要投入时间学习这个技能。
- 提高效率,节省成本:自动化测试可以 7x24 小时不间断地执行测试用例,替代大量重复的人工回归测试,尤其是在版本迭代频繁的项目中,能极大地解放人力。
- 提升测试覆盖率:可以轻松执行大量甚至边界情况的测试用例,这是人工测试难以做到的,从而发现更多潜在的 Bug。
- 提高软件质量:通过快速反馈,开发人员可以在早期阶段就修复缺陷,降低修复成本,提升最终产品的稳定性和可靠性。
- 回归测试的利器:每次代码更新后,运行自动化测试套件可以确保新代码没有破坏现有功能。
- 市场需求大:掌握自动化测试技能是软件测试工程师和开发工程师的“加分项”,薪资待遇和发展前景都很好。
自动化测试基础
在敲代码之前,我们需要理解几个核心概念。
测试金字塔
这是理解自动化测试分层的关键模型。
- 单元测试:金字塔的底层,占比最高,测试的是最小的代码单元(如一个函数、一个方法),由开发人员编写,执行速度快,隔离性强。
- 集成测试:中间层,测试的是多个模块或服务之间的交互和接口,测试你的代码如何与数据库、API 或其他库协作。
- 端到端测试:金字塔的顶层,占比最低,模拟真实用户的完整操作流程,从 UI 界面开始,到结束,模拟用户登录、浏览商品、下单、支付的全过程,这类测试最慢、最不稳定,但价值最高。
我们的重点:主要学习API 测试(属于集成测试)和 Web UI 自动化测试(属于端到端测试)。
自动化测试的适用场景
不是所有测试都适合自动化。
- 适合自动化的场景:
- 回归测试:核心功能,每次迭代都需要验证。
- 重复性高的测试:数据驱动的测试,如不同用户登录。
- 多平台/多浏览器兼容性测试。
- 性能测试、负载测试。
- 不适合自动化的场景:
- 探索性测试:需要人的直觉、经验和创造力。
- 一次性的测试。
- UI 频繁变动的测试(维护成本高)。
- 用户体验测试。
Python 测试环境搭建
这是所有工作的第一步,非常简单。
-
安装 Python:从 Python 官网 下载并安装最新稳定版,安装时记得勾选 "Add Python to PATH"。
-
安装虚拟环境工具
venv:-
venv是 Python 3.3+ 自带的虚拟环境管理工具,用于隔离项目依赖,避免包冲突。 -
在你的项目目录下,打开终端,运行:
# 创建一个名为 'venv' 的虚拟环境 python -m venv venv # 激活虚拟环境 # Windows: venv\Scripts\activate # macOS/Linux: source venv/bin/activate
-
激活后,你的终端提示符前会出现
(venv)。
-
-
安装必要的库:
- 在虚拟环境中使用
pip安装测试库。# 安装 pytest pip install pytest
安装 selenium
pip install selenium
安装 requests
pip install requests
安装 allure-pytest (用于生成漂亮的报告)
pip install allure-pytest
- 在虚拟环境中使用
核心库与工具详解
1 unittest - Python 内置的单元测试框架
unittest 是 Python 标准库的一部分,无需额外安装,它模仿 Java 的 JUnit 框架,结构严谨。
核心概念:
TestCase:测试用例的基类,你需要创建一个继承自unittest.TestCase的类。setUp()和tearDown():在每个测试方法执行前/后运行,用于初始化和清理资源。setUpClass()和tearDownClass():在所有测试方法执行前/后运行一次,通常用于耗时较长的全局设置。- 断言:
assertEqual,assertTrue,assertFalse,assertIn等方法,用于验证测试结果是否符合预期。
示例:
# test_calculator.py
import unittest
class TestCalculator(unittest.TestCase):
def setUp(self):
"""在每个测试前运行"""
self.calc = Calculator()
def test_add(self):
"""测试加法"""
result = self.calc.add(2, 3)
self.assertEqual(result, 5, "加法计算错误")
def test_subtract(self):
"""测试减法"""
result = self.calc.subtract(5, 3)
self.assertTrue(result == 2, "减法计算错误")
def test_divide_by_zero(self):
"""测试除零异常"""
with self.assertRaises(ZeroDivisionError):
self.calc.divide(10, 0)
# 假设我们有一个 Calculator 类
class Calculator:
def add(self, a, b):
return a + b
def subtract(self, a, b):
return a - b
def divide(self, a, b):
return a / b
if __name__ == '__main__':
unittest.main()
运行:
python -m unittest test_calculator.py
2 pytest - 功能强大且流行的测试框架
pytest 是目前 Python 社区最流行的测试框架,它比 unittest 更简洁、更灵活、功能更强大。
核心优势:
- 简洁的语法:无需继承
TestCase,函数名以test_开头即可。 - 强大的
fixtures:fixtures是pytest的核心,可以灵活地管理测试资源(类似setUp/tearDown,但更强大)。 - 丰富的插件生态:可以轻松集成覆盖率报告、并行执行、Allure 报告等。
- 内置丰富的断言:当断言失败时,会提供详细的错误信息。
示例:
# test_calculator_pytest.py
import pytest
# 直接定义一个 fixture,scope="function" 表示每个测试函数运行前都执行一次
@pytest.fixture
def calculator():
"""提供一个 calculator 实例给测试函数使用"""
print("正在初始化 Calculator...")
return Calculator()
def test_add(calculator):
"""测试加法"""
assert calculator.add(2, 3) == 5
def test_subtract(calculator):
"""测试减法"""
assert calculator.subtract(5, 3) == 2
# 使用内置的 raises fixture 来测试异常
def test_divide_by_zero(calculator):
"""测试除零异常"""
with pytest.raises(ZeroDivisionError):
calculator.divide(10, 0)
# Calculator 类定义同上...
运行:
# 自动发现并运行当前目录下所有 test_*.py 或 *_test.py 文件 pytest
建议:直接学习 pytest,因为它更现代、更高效,完全能满足从单元测试到 UI/API 测试的所有需求。
3 Selenium - Web 自动化测试利器
Selenium 是一个用于 Web 应用程序测试的工具,它可以直接在浏览器中运行,就像一个真实用户一样。
工作原理:通过 WebDriver 作为浏览器和你的脚本之间的“桥梁”,你的脚本通过 WebDriver API 控制浏览器(打开网页、点击元素、输入文本等)。
安装浏览器驱动:
- ChromeDriver: 下载地址 Chrome for Testing availability
- GeckoDriver (Firefox): 下载地址 Mozilla Geckodriver Releases
- 注意:驱动版本需要与你的浏览器版本大致匹配,下载后,将其路径添加到系统环境变量
PATH中,或放在脚本同级目录下。
示例:
# test_baidu_search.py
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 使用 pytest fixture 管理浏览器实例
@pytest.fixture
def browser():
"""初始化并返回一个浏览器实例"""
driver = webdriver.Chrome() # 确保已安装 ChromeDriver
driver.implicitly_wait(10) # 隐式等待,全局生效
yield driver
driver.quit() # 测试结束后关闭浏览器
def test_baidu_search(browser):
"""测试百度搜索"""
browser.get("https://www.baidu.com")
# 使用显式等待,更可靠
search_box = WebDriverWait(browser, 10).until(
EC.presence_of_element_located((By.ID, "kw"))
)
search_box.send_keys("Python 自动化测试")
search_box.send_keys(Keys.ENTER)
# 等待结果页面出现
WebDriverWait(browser, 10).until(
EC.title_contains("Python 自动化测试")
)
assert "Python 自动化测试" in browser.title
运行:
pytest test_baidu_search.py
4 Requests - API 接口测试神器
Requests 是 Python 中最优雅、最简单的 HTTP 库,非常适合用来测试 RESTful API。
核心功能:发送 GET, POST, PUT, DELETE 等请求,并接收响应。
示例:
# test_api.py
import pytest
import requests
BASE_URL = "https://jsonplaceholder.typicode.com"
def test_get_posts():
"""测试获取所有帖子"""
response = requests.get(f"{BASE_URL}/posts")
assert response.status_code == 200
assert isinstance(response.json(), list)
assert len(response.json()) > 0
def test_get_single_post():
"""测试获取单个帖子"""
post_id = 1
response = requests.get(f"{BASE_URL}/posts/{post_id}")
assert response.status_code == 200
data = response.json()
assert data['id'] == post_id
assert 'title' in data
def test_create_post():
"""测试创建一个新帖子"""
payload = {
"title": "foo",
"body": "bar",
"userId": 1
}
response = requests.post(f"{BASE_URL}/posts", json=payload)
assert response.status_code == 201 # HTTP 201 Created
data = response.json()
assert data['title'] == "foo"
assert 'id' in data # 新创建的资源通常会有一个 ID
运行:
pytest test_api.py
5 Appium - 移动应用自动化测试
Appium 是一个移动端的自动化测试框架,支持 iOS 和 Android 平台,它的原理与 Selenium 类似,通过一个 Appium Server 来控制手机或模拟器。
特点:
- 跨平台:一套 API 可以同时测试 iOS 和 Android。
- 不应用源码:基于黑盒测试,通过 Instrumentation (Android) 和 UIAutomation (iOS) 来驱动。
- 支持多种语言:包括 Python, Java, Ruby, JS 等。
Python 使用:
- 安装:
pip install Appium-Python-Client - 需要单独安装 Appium Server 并启动。
由于移动端测试环境搭建相对复杂,建议在学习了 Web 自动化后再进行探索。
实战项目:构建一个 Web UI 自动化测试框架
我们将使用 pytest + Selenium + Allure + POM 模式来构建一个结构清晰的框架。
项目结构:
/web_ui_framework
|-- pages/ # 存放 Page Object 模型
| |-- __init__.py
| |-- base_page.py # 封装通用操作 (find_element, click 等)
| |-- baidu_page.py # 百度首页的元素和操作
|-- tests/ # 存放测试用例
| |-- __init__.py
| |-- test_baidu.py # 百度搜索的测试用例
|-- conftest.py # pytest 的配置文件,定义全局 fixtures
|-- config.py # 配置文件 (如 URL)
|-- requirements.txt # 项目依赖
|-- pytest.ini # pytest 的配置文件
步骤 1: 创建 config.py
# config.py BASE_URL = "https://www.baidu.com"
步骤 2: 创建 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
def find_element(self, *locator):
"""查找单个元素"""
return self.driver.find_element(*locator)
def find_elements(self, *locator):
"""查找多个元素"""
return self.driver.find_elements(*locator)
def click(self, *locator):
"""点击元素"""
element = WebDriverWait(self.driver, 10).until(
EC.element_to_be_clickable(locator)
)
element.click()
def input_text(self, text, *locator):
"""输入文本"""
element = WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located(locator)
)
element.clear()
element.send_keys(text)
步骤 3: 创建 pages/baidu_page.py (百度页面对象)
# pages/baidu_page.py
from selenium.webdriver.common.by import By
from .base_page import BasePage
class BaiduPage(BasePage):
# 定位器
search_input_locator = (By.ID, "kw")
search_button_locator = (By.ID, "su")
result_link_locator = (By.CSS_SELECTOR, "#content_left > div > h3 > a")
def search(self, keyword):
"""执行搜索操作"""
self.input_text(keyword, *self.search_input_locator)
self.click(*self.search_button_locator)
def get_first_result_title(self):
"""获取第一个搜索结果的标题"""
first_result = self.find_element(*self.result_link_locator)
return first_result.text
步骤 4: 创建 conftest.py (全局 fixture)
# conftest.py
import pytest
from selenium import webdriver
from config import BASE_URL
@pytest.fixture
def driver():
"""全局浏览器 fixture"""
d = webdriver.Chrome()
d.maximize_window()
d.get(BASE_URL)
yield d
d.quit()
步骤 5: 创建 tests/test_baidu.py (测试用例)
# tests/test_baidu.py
from pages.baidu_page import BaiduPage
def test_baidu_search(driver):
"""测试百度搜索结果"""
baidu_page = BaiduPage(driver)
# 搜索关键词
baidu_page.search("Python")
# 获取并断言第一个结果
first_title = baidu_page.get_first_result_title()
assert "Python" in first_title
步骤 6: 运行并生成报告
- 安装 allure:
# 下载 allure-commandline 并添加到 PATH # 或者使用 pip (不推荐,功能不全) pip install allure-pytest
- 运行测试:
# 生成原始数据报告 pytest --alluredir=./results
- 生成 HTML 报告:
# 在项目根目录下执行 allure generate results -o report --clean
- 查看报告:
allure open report
这会打开一个漂亮的、可交互的 HTML 报告页面。
实战项目:构建一个 API 自动化测试框架
API 测试框架更侧重于数据的校验和流程的自动化。
项目结构:
/api_framework
|-- data/ # 测试数据
| |-- test_data.json
|-- tests/ # 测试用例
| |-- __init__.py
| |-- test_api.py
|-- utils/ # 工具类
| |-- __init__.py
| |-- request_handler.py # 封装 requests
|-- config.py # 配置文件 (如 BASE_URL)
|-- requirements.txt
|-- pytest.ini
步骤 1: 创建 utils/request_handler.py (封装请求)
# utils/request_handler.py
import requests
import json
class RequestHandler:
def __init__(self, base_url):
self.base_url = base_url
self.session = requests.Session()
def request(self, method, url, **kwargs):
"""发送请求"""
full_url = self.base_url + url
response = self.session.request(method, full_url, **kwargs)
# 可以在这里添加日志、响应断言等
return response
def get(self, url, **kwargs):
return self.request('GET', url, **kwargs)
def post(self, url, **kwargs):
return self.request('POST', url, **kwargs)
# ... 其他方法 PUT, DELETE 等
步骤 2: 创建 data/test_data.json
[
{
"name": "获取所有帖子",
"method": "GET",
"url": "/posts",
"expected_status": 200,
"expected_key": "id"
},
{
"name": "创建新帖子",
"method": "POST",
"url": "/posts",
"payload": {
"title": "自动化测试框架",
"body": "这是一个由 Python 构建的 API 测试框架",
"userId": 1
},
"expected_status": 201,
"expected_key": "title"
}
]
步骤 3: 创建 tests/test_api.py (数据驱动测试)
# tests/test_api.py
import pytest
import json
from config import BASE_URL
from utils.request_handler import RequestHandler
@pytest.fixture(scope="session")
def api_client():
"""全局 API 客户端 fixture"""
return RequestHandler(BASE_URL)
# 使用 pytest.mark.parametrize 进行参数化
@pytest.mark.parametrize("test_case",
json.load(open('../data/test_data.json', 'r', encoding='utf-8'))
)
def test_api(api_client, test_case):
"""执行 API 测试用例"""
print(f"\n正在执行测试: {test_case['name']}")
if test_case['method'].upper() == 'GET':
response = api_client.get(test_case['url'])
elif test_case['method'].upper() == 'POST':
response = api_client.post(test_case['url', json=test_case['payload']])
# 断言状态码
assert response.status_code == test_case['expected_status']
# 断言响应体中包含某个 key
assert test_case['expected_key'] in response.json()
步骤 4: 运行测试
pytest tests/test_api.py -v
高级主题与最佳实践
1 测试报告
- Allure:目前最流行的报告生成工具,能生成交互式、内容丰富的报告,包含测试步骤、截图、日志、附件等,与
pytest-allure或pytest-allure-pytest插件配合使用。 - HTMLTestRunner:一个老牌的生成 HTML 报告的库,简单易用,但功能相对 Allure 较弱。
2 持续集成
自动化测试的价值在于持续执行,将你的测试脚本集成到 CI/CD 流程中。
- 工具:Jenkins, GitLab CI, GitHub Actions。
- 流程:当代码被推送到仓库时,CI 服务器会自动拉取代码、安装依赖、运行测试套件,并生成报告和通知,如果测试失败,可以阻止代码合并。
3 Page Object Model (POM) 设计模式
这是 Web UI 自动化测试中最重要的设计模式。
- 核心思想:将页面的元素定位和业务操作封装在一个类中(Page Object),测试用例只负责调用这些操作,不关心具体的实现细节。
- 好处:
- 可维护性:当 UI 变化时,只需修改对应的 Page Object 类,而不需要修改所有测试用例。
- 可读性:测试用例更像业务描述,代码更清晰。
- 复用性:页面操作可以在不同测试用例间复用。
我们在 实战项目 5 中已经实践了 POM。
4 参数化与数据驱动
将测试数据和测试逻辑分离,让一套测试逻辑可以运行多组数据。
- 工具:
pytest.mark.parametrize。 - 数据源:可以是列表、元组、字典,也可以是来自 CSV、Excel、JSON 文件或数据库的数据,这使得测试更加灵活和全面。
我们在 实战项目 6 中使用了 JSON 文件进行数据驱动。
5 Mock 与 Stub (模拟依赖)
在测试中,我们常常会遇到一些难以控制或耗时的外部依赖,如数据库、第三方 API、邮件服务等,Mock 技术可以帮助我们模拟这些依赖。
- 工具:
unittest.mock(Python 内置),pytest-mock。 - 作用:用一个“假”的对象替换掉真实的对象,让测试可以独立、快速、稳定地运行,而不受外部环境影响。
学习资源与社区
- 官方文档:
- 教程与博客:
- Real Python: 有大量高质量的 Python 教程,包括测试。
- TesterHome: 国内非常活跃的测试技术社区,有大量关于自动化测试的分享。
- CSDN/掘金/知乎:搜索关键词 "Python 自动化测试",可以找到很多实战文章和教程。
- 书籍:
- 《Python 自动化测试实战》
- 《Selenium 自动化测试——基于 Python》
- 社区:
- Stack Overflow: 解决具体技术问题的首选。
- GitHub: 阅读优秀的开源测试项目源码是学习的最佳途径之一。
总结与学习路径建议
学习路径建议:
-
第一阶段:Python 基础与测试理论
- 掌握 Python 基础语法、函数、类、模块。
- 理解软件测试的基本概念(黑盒、白盒、回归测试等)。
- 学习
unittest或直接上手pytest,掌握单元测试的编写方法。
-
第二阶段:Web 自动化测试入门
- 学习
Selenium的基本 API:find_element,click,send_keys等。 - 理解显式等待和隐式等待的区别,优先使用显式等待。
- 编写几个简单的 Web UI 自动化脚本,如登录、搜索。
- 学习
-
第三阶段:构建框架与高级 Web 自动化
- 学习并实践 POM 设计模式,重构你的脚本。
- 封装
BasePage,提高代码复用性。 - 集成
pytest,学习fixture的使用。 - 学习
pytest的参数化功能,实现数据驱动。 - 集成
Allure,生成专业的测试报告。
-
第四阶段:API 自动化测试
- 学习
Requests库,熟练掌握 GET/POST/PUT/DELETE 等请求方法。 - 编写 API 测试用例,重点校验响应状态码、响应头、响应体。
- 使用
pytest和 JSON/Excel 文件实现 API 的数据驱动测试。
- 学习
-
第五阶段:持续集成与高级主题
- 学习使用 GitHub Actions 或 GitLab CI 配置简单的 CI 流水线。
- 学习使用
Mock技术来隔离外部依赖。 - 探索 性能测试 (如
locust) 或 移动端自动化测试 (如Appium)。
最重要的建议:
- 多动手实践:看再多教程,不如亲手写一个项目。
- 阅读优秀源码:去 GitHub 上找一些开源的测试框架学习别人的代码风格和设计思路。
- 保持好奇心:技术更新很快,持续学习新的工具和最佳实践。
祝你学习顺利,早日成为自动化测试专家!
