news 2026/4/17 18:19:21

Pytest 自动化测试框架的使用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Pytest 自动化测试框架的使用

Pytest和Unittest测试框架的区别?

如何区分这两者,很简单unittest作为官方的测试框架,在测试方面更加基础,并且可以再次基础上进行二次开发,同时在用法上格式会更加复杂;而pytest框架作为第三方框架,方便的地方就在于使用更加灵活,并且能够对原有unittest风格的测试用例有很好的兼容性,同时在扩展上更加丰富,可通过扩展的插件增加使用的场景,比如一些并发测试等;

Pytest 安装

pip安装:

1

pip install pytest

测试安装成功:

1

2

3

pytest--help

py.test--help

检查安装版本:

1

pytest--version

Pytest 示例

Pytest编写规则:

  • 测试文件以test_开头(以_test为结尾)
  • 测试的类以Test开头;
  • 测试的方法以test_开头
  • 断言使用基本的assert

test_example.py

1

2

3

4

5

6

defcount_num(a:list)->int:

returnlen(a)

deftest_count():

assertcount_num([1,2,3]) !=3

执行测试:

1

pytest test_example.py

执行结果:

C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest>pytest test_example.py -v
================================================================= test session starts =================================================================
platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- d:\coding\python3.6\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
plugins: Faker-8.11.0
collected 1 item

test_example.py::test_count FAILED [100%]

====================================================================== FAILURES =======================================================================
_____________________________________________________________________ test_count ______________________________________________________________________

def test_count():
> assert count_num([1, 2, 3]) != 3
E assert 3 != 3
E + where 3 = count_num([1, 2, 3])

test_example.py:11: AssertionError
=============================================================== short test summary info ===============================================================
FAILED test_example.py::test_count - assert 3 != 3
================================================================== 1 failed in 0.16s ==================================================================

备注:

  • .代表测试通过,F代表测试失败;
  • -v显示详细的测试信息, -h显示pytest命令详细的帮助信息;

标记

默认情况下,pytest会在当前目录下寻找以test_为开头(以_test结尾)的测试文件,并且执行文件内所有以test_为开头(以_test为结尾)的所有函数和方法;

指定运行测试用例,可以通过::显示标记(文件名::类名::方法名)(文件名::函数名)

1

pytest test_example3.py::test_odd

指定一些测试用例测试运行,可以使用-k模糊匹配

1

pytest-k example

通过pytest.mark.skip()或者pytest.makr.skipif()条件表达式,跳过指定的测试用例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

importpytest

test_flag=False

@pytest.mark.skip()

deftest_odd():

num=random.randint(0,100)

assertnum%2==1

@pytest.mark.skipif(test_flagisFalse, reason="test_flag is False")

deftest_even():

num=random.randint(0,1000)

assertnum%2==0

通过pytest.raises()捕获测试用例可能抛出的异常

1

2

3

4

5

6

7

deftest_zero():

num=0

with pytest.raises(ZeroDivisionError) as e:

num=1/0

exc_msg=e.value.args[0]

print(exc_msg)

assertnum==0

预先知道测试用例会失败,但是不想跳过,需要显示提示信息,使用pytest.mark.xfail()

1

2

3

4

5

@pytest.mark.xfail()

deftest_sum():

random_list=[random.randint(0,100)forxinrange(10)]

num=sum(random_list)

assertnum <20

对测试用例进行多组数据测试,每组参数都能够独立执行一次(可以避免测试用例内部执行单组数据测试不通过后停止测试)

1

2

3

4

@pytest.mark.parametrize('num,num2', [(1,2),(3,4)])

deftest_many_odd(num:int, num2:int):

assertnum%2==1

assertnum2%2==0

固件(Fixture)

固件就是一些预处理的函数,pytest会在执行测试函数前(或者执行后)加载运行这些固件,常见的应用场景就有数据库的连接和关闭(设备连接和关闭)

简单使用

1

2

3

4

5

6

7

8

importpytest

@pytest.fixture()

defpostcode():

return"hello"

deftest_count(postcode):

assertpostcode=="hello"

按照官方的解释就是当运行测试函数,会首先检测运行函数的参数,搜索与参数同名的fixture,一旦pytest找到,就会运行这些固件,获取这些固件的返回值(如果有),并将这些返回值作为参数传递给测试函数;

预处理和后处理

接下来进一步验证关于官方的说法:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

importpytest

@pytest.fixture()

defconnect_db():

print("Connect Database in .......")

yield

print("Close Database out .......")

defread_database(key:str):

p_info={

"name":"zhangsan",

"address":"China Guangzhou",

"age":99

}

returnp_info[key]

deftest_count(connect_db):

assertread_database("name")=="zhangsan"

执行测试函数结果:

============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Coding\Python3.6\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
plugins: Faker-8.11.0
collecting ... collected 1 item

test_example.py::test_count Connect Database in .......
PASSED [100%]Close Database out .......


============================== 1 passed in 0.07s ==============================

备注:

  • 首先从结果上看验证了官方的解释,pytest执行测试函数前会寻找同名的固件加载运行;
  • connect_db固件中有yield,这里pytest默认会判断yield关键词之前的代码属于预处理,会在测试前执行,yield之后的代码则是属于后处理,将在测试后执行;

作用域

从前面大致了解了固件的作用,抽离出一些重复的工作方便复用,同时pytest框架中为了更加精细化控制固件,会使用作用域来进行指定固件的使用范围,(比如在这一模块中的测试函数执行一次即可,不需要模块中的函数重复执行)更加具体的例子就是数据库的连接,这一连接的操作可能是耗时的,我只需要在这一模块的测试函数运行一次即可,不需要每次都运行。

而定义固件是,一般通过scop参数来声明作用,常用的有:

  • function: 函数级,每个测试函数都会执行一次固件;
  • class: 类级别,每个测试类执行一次,所有方法都可以使用;
  • module: 模块级,每个模块执行一次,模块内函数和方法都可使用;
  • session: 会话级,一次测试只执行一次,所有被找到的函数和方法都可用。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

importpytest

@pytest.fixture(scope="function")

deffunc_scope():

print("func_scope")

@pytest.fixture(scope="module")

defmod_scope():

print("mod_scope")

@pytest.fixture(scope="session")

defsess_scope():

print("session_scope")

deftest_scope(sess_scope, mod_scope, func_scope):

pass

deftest_scope2(sess_scope, mod_scope, func_scope):

pass

执行结果:

============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Coding\Python3.6\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
plugins: Faker-8.11.0
collecting ... collected 2 items

test_example2.py::test_scope session_scope
mod_scope
func_scope
PASSED [ 50%]
test_example2.py::test_scope2 func_scope
PASSED [100%]

============================== 2 passed in 0.07s ==============================

从这里可以看出module,session作用域的固件只执行了一次,可以验证官方的使用介绍

自动执行

有人可能会说,这样子怎么那么麻烦,unittest框架中直接定义setUp就能自动执行预处理,同样的pytest框架也有类似的自动执行; pytest框架中固件一般通过参数autouse控制自动运行。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

importpytest

@pytest.fixture(scope='session', autouse=True)

defconnect_db():

print("Connect Database in .......")

yield

print("Close Database out .......")

deftest1():

print("test1")

deftest2():

print("test")

执行结果:

============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Coding\Python3.6\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
plugins: Faker-8.11.0
collecting ... collected 2 items

test_example.py::test1 Connect Database in .......
PASSED [ 50%]test1

test_example.py::test2 PASSED [100%]test
Close Database out .......


============================== 2 passed in 0.07s ==============================

从结果看到,测试函数运行前后自动执行了connect_db固件;

参数化

前面简单的提到过了@pytest.mark.parametrize通过参数化测试,而关于固件传入参数时则需要通过pytest框架中内置的固件request,并且通过request.param获取参数

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

importpytest

@pytest.fixture(params=[

('redis','6379'),

('elasticsearch','9200')

])

defparam(request):

returnrequest.param

@pytest.fixture(autouse=True)

defdb(param):

print('\nSucceed to connect %s:%s'%param)

yield

print('\nSucceed to close %s:%s'%param)

deftest_api():

assert1==1

执行结果:

============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Coding\Python3.6\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
plugins: Faker-8.11.0
collecting ... collected 2 items

test_example.py::test_api[param0]
Succeed to connect redis:6379
PASSED [ 50%]
Succeed to close redis:6379

test_example.py::test_api[param1]
Succeed to connect elasticsearch:9200
PASSED [100%]
Succeed to close elasticsearch:9200


============================== 2 passed in 0.07s ==============================

这里模拟连接redis和elasticsearch,加载固件自动执行连接然后执行测试函数再断开连接。

总结

对于开发来说为什么也要学习自动化测试这一块,很重要的一点就是通过自动化测试节省一些重复工作的时间,同时对于优化代码结构,提高代码覆盖率,以及后续项目重构都是有着很重要的意义,同时理解pytest和unittest在基础上有何区别有助于不同的业务场景中选择适合自己的测试工具。

感谢每一个认真阅读我文章的人!!!

作为一位过来人也是希望大家少走一些弯路,如果你不想再体验一次学习时找不到资料,没人解答问题,坚持几天便放弃的感受的话,在这里我给大家分享一些自动化测试的学习资源,希望能给你前进的路上带来帮助。

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

视频文档获取方式:
这份文档和视频资料,对于想从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!以上均可以分享,点下方小卡片即可自行领取。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/13 17:28:47

PLG log server note

目录三者的架构图Principle of operationexecute pack init and InstalllokiPromtailloki server startpromtail server startpromtail of windows.deb grafana install.rpm grafana installGrafana server startConfig notePLG是一套开源且成熟的日志监控系统&#xff0c;根据…

作者头像 李华
网站建设 2026/4/17 17:34:11

能源数采网关赋能能源智慧管理与低碳转型

在“双碳”目标背景下&#xff0c;工业能源管理已成为企业降本增效、实现绿色制造的关键环节。然而&#xff0c;传统能源数据采集依赖人工抄表、系统孤立、分析滞后&#xff0c;难以实现精细化管理和实时优化&#xff0c;导致能源浪费严重、成本居高不下。 以能源数采网关为基础…

作者头像 李华
网站建设 2026/4/17 16:50:27

“潘金莲”扮演者因戏生情,与武松在一起,今五十三岁却过成这样!

在经典影视的璀璨星河中&#xff0c;98版《水浒传》宛如一颗耀眼的明珠&#xff0c;其中“潘金莲”与“武松”的对手戏更是令人印象深刻。而扮演“潘金莲”的王思懿&#xff0c;竟因戏生情&#xff0c;与“武松”的扮演者丁海峰传出绯闻&#xff0c;这段故事如同投入平静湖面的…

作者头像 李华
网站建设 2026/4/16 18:07:49

学霸同款10个降AIGC网站 千笔AI帮你降AI率

AI降重工具&#xff1a;让论文更自然&#xff0c;让学术更纯粹 在当前的学术环境中&#xff0c;越来越多的研究生开始关注论文的AIGC率和查重率 面对这一挑战&#xff0c;AI降重工具应运而生&#xff0c;它们通过智能算法对文本进行深度处理&#xff0c;不仅能够有效降低AI痕迹…

作者头像 李华
网站建设 2026/4/16 16:37:32

python+vue开发的新农村自建房改造管理系统-pycharm DJANGO FLASK

文章目录 新农村自建房改造管理系统的技术框架后端技术实现要点前端Vue.js核心功能数据库与部署方案系统特色功能 大数据系统开发流程主要运用技术介绍源码文档获取定制开发/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01; 新农村自建房改造管理系统…

作者头像 李华