头像
淇迹时刻
-- : -- : --
切换主题色
-- : -- : --

第二阶段:fixture机制与参数化

最后更新于:

第二阶段:fixture机制与参数化

一、fixture机制

1.1 什么是fixture?

fixture是pytest最核心的特性,用于实现测试的前置条件准备后置清理。它可以看作是测试用例的"依赖注入"系统。

1.2 基本用法

 1import pytest
 2
 3@pytest.fixture
 4def setup():
 5    # 前置准备
 6    print("\nSetup: 准备测试环境")
 7    data = {"name": "test", "value": 42}
 8    yield data  # 返回数据给测试用例
 9    # 后置清理
10    print("\nTeardown: 清理测试环境")
11
12def test_example(setup):
13    print(f"测试中使用fixture数据: {setup}")
14    assert setup["value"] == 42

1.3 fixture作用域

作用域说明使用场景
function每个测试函数执行一次(默认)每个测试需要独立的对象实例
class每个测试类执行一次同一类的测试共享同一个资源
module每个测试模块执行一次模块级别的共享资源
session整个测试会话执行一次全局共享资源,如数据库连接

1.4 autouse自动执行

1@pytest.fixture(autouse=True)
2def auto_fixture():
3    print("\n[Auto] 自动执行的fixture")
4    yield
5    print("\n[Auto] 自动清理")

1.5 fixture依赖

 1@pytest.fixture
 2def db_connection():
 3    conn = create_connection()
 4    yield conn
 5    conn.close()
 6
 7@pytest.fixture
 8def test_data(db_connection):
 9    db_connection.insert(test_data)
10    yield test_data
11    db_connection.delete(test_data)

二、参数化测试

2.1 基本用法

1import pytest
2
3@pytest.mark.parametrize("input,expected", [
4    (2, 4),
5    (3, 9),
6    (4, 16),
7])
8def test_square(input, expected):
9    assert input ** 2 == expected

2.2 多参数参数化

1@pytest.mark.parametrize("a,b,expected", [
2    (2, 3, 5),
3    (0, 0, 0),
4    (-1, 1, 0),
5])
6def test_add(a, b, expected):
7    assert a + b == expected

2.3 组合参数化

1@pytest.mark.parametrize("a", [1, 2, 3])
2@pytest.mark.parametrize("b", [4, 5])
3def test_combine(a, b):
4    # 测试组合: (1,4), (1,5), (2,4), (2,5), (3,4), (3,5)
5    assert a + b > 0

2.4 参数化ID

1@pytest.mark.parametrize("input,expected", [
2    (2, 4),
3    (3, 9),
4], ids=["two_squared", "three_squared"])
5def test_square(input, expected):
6    assert input ** 2 == expected

三、断言系统

3.1 基本断言

1assert a == b           # 相等断言
2assert a != b           # 不相等断言
3assert a in b           # 包含断言
4assert a is None        # None断言
5assert isinstance(a, int)  # 类型断言

3.2 带消息的断言

1assert result == expected, f"期望{expected},实际{result}"

3.3 异常断言

 1# 断言抛出异常
 2with pytest.raises(ValueError):
 3    risky_operation()
 4
 5# 断言异常消息
 6with pytest.raises(ValueError, match="divide by zero"):
 7    divide(10, 0)
 8
 9# 获取异常信息
10with pytest.raises(ValueError) as exc_info:
11    divide(10, 0)
12assert "Cannot divide by zero" in str(exc_info.value)

3.4 近似值断言

1# 使用pytest的approx
2from pytest import approx
3assert 0.1 + 0.2 == approx(0.3)
4assert 0.1 + 0.2 == approx(0.3, rel=1e-6)
5assert 0.1 + 0.2 == approx(0.3, abs=1e-9)

四、示例代码

4.1 fixture示例

 1# tests/test_fixture_demo.py
 2import pytest
 3from src.calculator import Calculator
 4
 5@pytest.fixture
 6def calculator():
 7    calc = Calculator()
 8    return calc
 9
10@pytest.fixture(scope="module")
11def module_data():
12    print("\n[Module Setup] 准备模块级数据")
13    data = {"start_value": 100}
14    yield data
15    print("\n[Module Teardown] 清理模块级数据")
16
17def test_add_with_fixture(calculator):
18    result = calculator.add(2, 3)
19    assert result == 5

4.2 参数化示例

 1# tests/test_parametrize_demo.py
 2import pytest
 3from src.calculator import Calculator
 4
 5@pytest.fixture
 6def calculator():
 7    return Calculator()
 8
 9@pytest.mark.parametrize("a,b,expected", [
10    (2, 3, 5),
11    (0, 0, 0),
12    (-1, 1, 0),
13    (10, -5, 5),
14])
15def test_add_parametrize(calculator, a, b, expected):
16    result = calculator.add(a, b)
17    assert result == expected

五、易错点与注意事项

5.1 fixture常见错误

  1. 作用域选择不当:需要共享资源时使用了function作用域
  2. fixture命名冲突:不同层级的conftest.py中有同名fixture
  3. 忘记yield:fixture函数没有yield语句,导致测试无法获取数据

5.2 参数化常见错误

  1. 参数数量不匹配:parametrize装饰器的参数与测试函数参数数量不一致
  2. 数据格式错误:参数列表中的元组长度不一致
  3. 缺少import:忘记导入pytest模块

5.3 断言常见错误

  1. 浮点数比较:直接比较浮点数可能导致精度问题,使用approx
  2. 异常断言位置pytest.raises()需要包裹会抛出异常的代码
  3. 断言消息过长:断言消息应简洁明了

六、小结

本阶段学习了pytest的核心功能,包括:

  • fixture机制及作用域控制
  • autouse自动执行
  • 参数化测试
  • 异常断言和近似值断言
最新文章