一个计算机技术爱好者与学习者

0%

好好学Python:Python单元测试框架之pytest

1. pytest简介

The pytest framework makes it easy to write small, readable tests, and can scale to support complex functional testing for applications and libraries.

pytest是一种卓越的Python测试框架,它提供了简单、高效的方式来编写可以扩展的测试用例。

本文学习pytest的测试用例写法,内容整理自 chatgpt gpt-4-0613 。

相关文档:

2. pytest基本测试

2.1. 准备一个模块

准备一个mathlib模块,包含一个求和函数add():

1
2
3
# mathlib.py
def add(a, b):
return a + b

2.2. 编写测试用例

Python中编写测试用例,一种常见的方式是创建一个以test_为前缀的函数,这个函数应包含测试用例的名字和内部执行逻辑。

我们想要创建一个测试用例来检验 add 函数,我们可以创建一个 test_mathlib.py 文件:

1
2
3
4
5
6
# test_mathlib.py
import mathlib

def test_add():
res = mathlib.add(5, 3)
assert res == 8

2.3. 执行测试

1
pytest test_mathlib.py

2.4. 丰富测试用例

为了使测试更丰富,我们可以使用 @pytest.mark.parametrize 装饰器为函数参数提供多组值:

1
2
3
4
5
6
7
8
9
10
11
12
# test_mathlib.py
import mathlib
import pytest

@pytest.mark.parametrize("a, b, expected", [
(5, 3, 8),
(10, 20, 30),
(1, -1, 0)
])
def test_add(a, b, expected):
res = mathlib.add(a, b)
assert res == expected

3. pytest进阶测试

3.1. Fixture

Fixture(预置) 是 pytest 提供的一种特殊的函数,它将测试前的准备工作和解除步骤打包成一个函数,以供测试用例调用。这样做可以提高测试的可重用性和代码的可读性。

例如,我们要为数据库相关的测试都创建一个测试数据库,并在测试结束后清理掉,可以写个fixture如下:

1
2
3
4
5
@pytest.fixture
def db():
db = setup_database()
yield db
teardown_database(db)

然后在测试函数中使用这个 db fixture:

1
2
3
def test_database(db):
# Now you can interact with the db object, which is set up
# at the beginning of the test and will be torn down at the end.

3.2. Mocking

Mocking(模拟) 是一种强大的技术,它可以模拟我们在测试中所依赖的部分的行为。例如,我们的函数可能依赖于一个第三方服务或者数据库,在测试环境中,很可能无法启动这些服务。这时,就可以用 Mock 对象替代这些服务或者数据库。pytest 提供了 unittest.mock 作为内置的 mocking 框架。

下面是一个简单的 mocking 例子,假设我们有一个打印函数 print_content(),我们并不希望在测试的时候真的打印出来:

1
2
3
4
5
6
from unittest.mock import MagicMock

def test_print_content():
print_content = MagicMock()
print_content("hello")
print_content.assert_called_with("hello")

3.3. Marker

在 pytest 中,Marker(标记)用于给测试用例添加元数据。比如最常见的 skip 和 xfail,它们会让 pytest 跳过或者期望失败的测试用例。

1
2
3
4
5
6
7
8
9
import pytest

@pytest.mark.skip(reason="No way to test this")
def test_the_unknown():
...

@pytest.mark.xfail
def test_feature_x():
...

@pytest.mark.asyncio 也是一个常用的内置装饰器,用于标记需要异步执行的函数。

Python3.5 版本引入了 async / await 关键字支持原生协程,它允许我们编写异步的代码,而不需要依赖于特定的包或者复杂的回调链。然而,pytest 是同步的,它不能原生支持 async / await 式的测试。这就是 pytest.mark.asyncio 装饰器的作用: 它让我们能够以同步的方式来测试异步的代码。

我们也可以自定义 marker。然后我们可以在运行 pytest 的时候指定参数 -m 来只运行有特定标记的测试用例,从而帮助我们更好地管理和运行我们的测试。

1
2
3
4
5
6
@pytest.mark.my_marker
def test_function():
...

# Run the test
pytest -m my_marker
  • 本文作者: 好好学习的郝
  • 原文链接: https://www.voidking.com/dev-python-pytest/
  • 版权声明: 本文采用 BY-NC-SA 许可协议,转载请注明出处!源站会即时更新知识点并修正错误,欢迎访问~
  • 微信公众号同步更新,欢迎关注~