Python-模块篇(测试工具篇、unittest、pytest)

1、测试框架-unittest

unittest是Python 标准库自带的单元测试框架,提供基础功能,适合简单测试。

  • TestFixture:准备\还原测试环境,比如setUp()、tearDow()
  • TestCase:测试用例
  • TestSuite:测试套件,用于组合多个测试用例
  • TestLoader:发现和加载测试用例
  • TestRunner:运行测试并输出结果(TextTestRunner输出纯文本,HTMLTestRunner输出HTML文件)
  • 基础用法示例:
import unittest

#必须继承unittest.TestCase
class TestMath(unittest.TestCase):
    # 测试前置:每个测试方法执行前运行
    def setUp(self):
        self.a = 3
        self.b = 5

    # 测试后置:每个测试方法执行后运行
    def tearDown(self):
        pass
    
    #测试方法必须以"test_"开头
    def test_addition(self):
        self.assertEqual(self.a + self.b, 8) #是否相等
        #其它断言:assertTrue(x)、assertIs(a, b)、assertIn(a, b)

    def test_division_by_zero(self):
        with self.assertRaises(ZeroDivisionError): #是否抛出指定异常
            self.a / 0

    @classmethod
    def setUpClass(cls):
        """整个测试类执行前运行一次"""
        print("测试类开始")

    @classmethod
    def tearDownClass(cls):
        """整个测试类执行后运行一次"""
        print("测试类结束")

if __name__ == "__main__":
    # 会运行当前文件中所有以 test_ 开头的方法
    unittest.main()

2、测试框架-pytest(pip install pytest)

pytest 是在 unittest 的基础上发展而来的,语法更简洁、功能更丰富。

基本规则

文件名:test_*.py 或 *_test.py

函数名:test_*

类名:Test*(类中方法也需以 test_ 开头)

断言

assert result == 8
assert flag is True
assert item in list
pytest.raises() #否抛出预期异常

其它

@pytest.mark.slow: 标记与分组
@pytest.mark.flaky(reruns=5, reruns_delay=2):失败重试5次


@pytest.fixture:管理测试前置/后置/依赖

import pytest

# 1. 默认Fixture:提供测试数据(每次依赖都会重新执行一次,返回全新对象)
@pytest.fixture
def sample_data():
    return {"name": "Alice", "age": 30}

def test_fixture_basic(sample_data): #使用fixture:直接在测试函数参数中注入
    assert sample_data["name"] == "Alice"
    assert sample_data["age"] == 30

# 2. Fixture带清理(使用yield)
@pytest.fixture
def db_connection():
    print("\n[前置] 连接数据库")
    conn = {"host": "localhost", "status": "connected"}
    yield conn  # 返回资源给测试函数
    print("\n[后置] 关闭数据库连接") #测试完成后再执行

def test_db(db_connection):
    assert db_connection["status"] == "connected"

# 3. Fixture作用域(scope)
@pytest.fixture(scope="module")  # module: 整个模块只执行一次
def module_scope_data():
    print("\n[module] 只执行一次")
    return {"key": "shared"}

def test_module_scope_1(module_scope_data):
    print("测试1:", module_scope_data)

def test_module_scope_2(module_scope_data):
    print("测试2:", module_scope_data)

# 4. 使用多个Fixture
@pytest.fixture
def user():
    return {"id": 1, "name": "Bob"}

@pytest.fixture
def user_with_age(user):
    user["age"] = 25
    return user

def test_multi_fixtures(user_with_age):
    assert user_with_age["name"] == "Bob"
    assert user_with_age["age"] == 25

# 5. 自动使用Fixture(无需在参数中声明、每个测试函数运行前自动执行)
@pytest.fixture(autouse=True)
def auto_log(request): #使用request.node.name获取测试函数的名字
    print(f"\n开始执行测试: {request.node.name}")

def test_autouse():
    print("最后的测试")

@pytest.mark.parametrize:参数化

import pytest

# 用一组数据运行同一个测试
@pytest.mark.parametrize("input_value, expected", [
    (1, 2),
    (2, 3),
    (3, 4),
])
def test_increment(input_value, expected): #传入参数名使用
    assert input_value + 1 == expected

# 组合参数(笛卡尔积)
@pytest.mark.parametrize("x", [1, 2]) 
#第1个装饰器,[1, 2]先逐个匹配10,再逐个匹配20 @pytest.mark.parametrize("y", [10, 20]) def test_add(x,y): print(f"x={x}, y={y}") """ x=1, y=10 x=2, y=10 x=1, y=20 x=2, y=20 """

 

跳过与预期失败

import pytest
import sys

# 1. 无条件跳过
@pytest.mark.skip(reason="此功能尚未实现")
def test_not_ready():
    pass

# 2. 条件跳过
@pytest.mark.skipif(sys.version_info < (3, 8), reason="需要Python 3.8+")
def test_python_version():
    assert True

# 3. 预期失败(bug已知,先标记)
@pytest.mark.xfail(reason="已知Bug #123,尚未修复")
def test_known_bug():
    assert 1 == 2  # 这个断言会失败,但pytest不会将其计为失败

# 4. 条件预期失败
@pytest.mark.xfail(sys.platform == "win32", reason="Windows上不支持")
def test_windows_only():
    assert True
"""
sys.platform == "win32" 为True:标记生效、失败显示为xfail,成功显示为X(预期失败但通过)
为True时、标记生效:reason内容才会在指定模式(-v)下进行输出
sys.platform == "win32" 为False:标记被忽略,测试正常执行
"""

 命令行常用参数

pytest #运行所有测试
pytest test_file.py    #运行指定文件
pytest test_file.py::test_func    #运行指定测试函数
pytest -v    #详细输出
pytest -s    #显示print输出(不捕获)
pytest -x    #遇到第一个失败就停止
pytest --maxfail=3   #遇到第3次失败后停止
pytest -m "slow"    #运行带smoke标记的测试
pytest -k "login"    #运行名称包含"login"的测试
pytest --pdb         #失败时进入调试器
pytest --html=report.html    #生成HTML报告(需安装pytest-html)
pytest --cov=my_module       #生成覆盖率报告(需安装pytest-cov)
pytest --reruns 3 --reruns-delay 1 #失败后重跑3次,每次重跑前等待1秒(安装pytest-rerunfailures)
pytest-xdist #并行执行测试插件

 

posted @ 2026-07-09 17:40  FengweiTech  阅读(8)  评论(0)    收藏  举报