pytest使用教程
一、pytest框架
1.1 pytest简介
pytest是Python生态中最强大、最流行的自动化测试框架,具有以下特点:
- 简洁语法:使用原生assert语句,无需记忆复杂的断言方法
- 自动发现:自动识别测试文件和测试函数
- 强大的fixture:依赖注入机制,实现测试前后置处理
- 丰富的插件生态:覆盖HTML报告、并行执行、覆盖率等场景
- 良好的兼容性:可直接运行unittest用例
1.2 安装方式
# 基础安装pipinstallpytest# 安装常用插件pipinstallpytest-html pytest-xdist pytest-rerunfailures1.3 命名规则
pytest采用约定优于配置的设计,测试用例需遵守以下命名规范:
| 类型 | 规则 | 示例 |
|---|---|---|
| 测试文件 | test_*.py或*_test.py | test_login.py,login_test.py |
| 测试函数 | test_开头 | def test_login_success() |
| 测试类 | Test开头,不含__init__ | class TestLogin: |
1.4 编写第一个测试用例
# test_sample.pydefadd(a,b):returna+bdeftest_add_positive_numbers():assertadd(2,3)==5deftest_add_negative_numbers():assertadd(-1,-1)==-2classTestMathOperations:deftest_multiply(self):assert2*3==61.5 运行测试
# 运行当前目录下所有测试pytest# 运行指定文件pytest test_sample.py# 运行指定函数pytest test_sample.py::test_add_positive_numbers# 运行指定类的方法pytest test_sample.py::TestMathOperations::test_multiply1.6 常用命令行参数
| 参数 | 作用 | 示例 |
|---|---|---|
-v | 显示详细信息 | pytest -v |
-s | 显示print输出 | pytest -s |
-x | 失败即停止 | pytest -x |
--lf | 只运行上次失败的用例 | pytest --lf |
-k | 按关键字筛选 | pytest -k "add" |
-m | 按标记筛选 | pytest -m smoke |
--html=report.html | 生成HTML报告 | pytest --html=report.html |
-n auto | 多线程并行执行 | pytest -n auto |
1.7 断言用法
deftest_assertions():# 基本断言assert1==1assert"hello"in"hello world"assert10>5# 断言异常withpytest.raises(ZeroDivisionError):10/0# 断言包含特定消息的异常withpytest.raises(ValueError,match="invalid"):raiseValueError("invalid value")1.8 Fixture(夹具)
1.8.1 基本用法
importpytest@pytest.fixturedeflogin_user():"""返回登录用户数据"""return{"username":"test","password":"123456"}deftest_login(login_user):username=login_user["username"]password=login_user["password"]assertusername=="test"1.8.2 Fixture作用域
| 作用域 | 生命周期 | 适用场景 |
|---|---|---|
function | 每个测试函数 | 临时数据 |
class | 每个测试类 | 类级共享状态 |
module | 每个测试文件 | 数据库连接 |
session | 整个测试会话 | WebDriver实例 |
@pytest.fixture(scope="session")defbrowser():driver=webdriver.Chrome()yielddriver driver.quit()1.8.3 带清理的Fixture
@pytest.fixturedefdb_connection():"""创建数据库连接,测试后自动关闭"""conn=create_connection()yieldconn conn.close()1.8.4 conftest.py
conftest.py是pytest的特殊文件,放在该文件中的fixture无需导入即可全局使用:
# tests/conftest.pyimportpytest@pytest.fixture(scope="session")defbase_url():return"https://api.example.com"@pytest.fixture(scope="function")defauth_token():return"Bearer test-token"1.9 参数化测试
importpytest@pytest.mark.parametrize("username,password,expected",[("admin","123456",True),("admin","wrong",False),("nonexistent","123456",False),("","123456",False),])deftest_login_parametrized(username,password,expected):result=authenticate(username,password)assertresult==expected1.10 测试标记
importpytest@pytest.mark.smokedeftest_login():pass@pytest.mark.regressiondeftest_checkout():pass@pytest.mark.skip(reason="功能尚未实现")deftest_feature_not_implemented():pass@pytest.mark.xfail(reason="已知bug")deftest_known_bug():pass运行带标记的测试:
pytest-msmoke# 只运行冒烟测试pytest-m"not slow"# 排除慢速测试1.11 生成测试报告
# HTML报告pytest--html=reports/test_report.html# Allure报告(需安装allure-pytest)pipinstallallure-pytest pytest--alluredir=reports/allure_results allure serve reports/allure_results1.12 实战示例:API接口测试
# test_api.pyimportpytestimportrequests@pytest.fixturedefapi_client():returnrequests.Session()@pytest.fixturedefbase_url():return"https://jsonplaceholder.typicode.com"classTestUserAPI:deftest_get_users(self,api_client,base_url):response=api_client.get(f"{base_url}/users")assertresponse.status_code==200assertisinstance(response.json(),list)deftest_get_user_by_id(self,api_client,base_url):response=api_client.get(f"{base_url}/users/1")assertresponse.status_code==200user=response.json()assertuser["id"]==1assert"name"inuserdeftest_create_user(self,api_client,base_url):payload={"name":"Test User","email":"test@example.com"}response=api_client.post(f"{base_url}/users",json=payload)assertresponse.status_code==201created_user=response.json()assertcreated_user["name"]==payload["name"]