目录
[第一章:Pytest console命令](#第一章:Pytest console命令)
[-v 参数](#-v 参数)
[-h 参数](#-h 参数)
[第二章. mark标记](#第二章. mark标记)
[编辑 @pytest.mark.patametrize](#编辑 @pytest.mark.patametrize)
[第三章 固件Fixture](#第三章 固件Fixture)
Pytest简单介绍

下载pytest
pip install pytest
第一章:Pytest console命令
默认需要test开头的py模块,test_开头的方法
1.pytest
执行pytest命令会自动匹配到test开头或者结尾的文件
将其作为测试用例文件执行,在测试用例文件中自动匹配到test开头的类,类中匹配到test开头的方法,然后执行
pass代表断言成功

失败:

-v 参数
会显示是哪个测试用例,信息更加详细一点

-h 参数
help 这是代表帮助的参数

其他一些参数:仅供参考

第二章. mark标记
pytest.mark是用来对测试方法进行标记的一个装饰器,主要作用是在测试用例执行过程中跳过标记的测试用例或做出判断以选择性的执行
标记测试函数
使用pytest --markers查看官方提供的mark

各个mark的具体含义如下:
|------------------------------------------------------------------------------|---------------------------------------------|
| mark | 含义 |
| @pytest.mark.filterwarings(warning) | 在标记的测试方法上添加警告过滤 |
| @pytest.mark.skip(reason=None) | 执行时跳过标记的测试方法,reason默认为空 |
| @pytest.mark.skipif(condition) | 通过条件判断是否跳过标记的测试方法,如果condition为真跳过,否则不跳过 |
| @pytest.mark.xfail(condition,reason=None,run=True, raises=None,strict=False) | 如果条件的condition为True,则将预期结果标记为False |
| @pytest.mark.parametrize(argnames,argvalues) | 测试函数参数化,即调用多次测试函数,依次传递不同的参数 |
| @pytest.mark.usefixtures(argnames,argvalues) | 将测试用例标记为需要指定的所有fixture,和直接使用fixture的效果一样。 |
| @pytest.mark.tryfirst | 标记一个挂钩实现函数,使得所标记的测试方法可以首先或尽早地执行 |
| @pytest.mark.trylast | 标记一个挂钩实现函数,使得标记的测试方法可以最后或尽可能晚执行,和tryfrist相反 |
@pytest.mark.skip
创建一个test_skip.py 添加这两个测试方法
使用pytest -v执行
import pytest
# 如果在测试方法前添加了@pytest.mark.skip(reason=None),则在执行过程中遇到该测试方法
# 时,跳过不执行
@pytest.mark.skip
def test_skip1():
assert 1 == 2
@pytest.mark.skip(reason="跳过该条测试用例")
def test_skip2():
assert 3 == 4
运行结果:

@pytest.mark.skipif
condition为True,跳过测试
condition为False, 不跳过
import pytest
import sys
my_list = [1, 3, 4, 5]
"""
源码解析:
class _SkipifMarkDecorator(MarkDecorator):
def __call__( # type: ignore[override]
self,
condition: str | bool = ...,
*conditions: str | bool,
reason: str = ...,
) -> MarkDecorator: ...
condition 可以是字符串也可以是bool类型
"""
# skipif对一些事物进行判断从而决定是否跳过测试方法,只有在满足条件下才会跳过
# condition = True, 跳过测试
@pytest.mark.skipif(condition=lambda: 1 in my_list, reason="1 在 my_list 中,跳过测试")
def test_skipif1():
assert 1 == 1
# condition为False, 所以不跳过
@pytest.mark.skipif('sys.platform != "win32" ')
def test_skipif2():
assert 2 == 2
# if __name__ == '__main__':
# print(sys.platform) # win32
@pytest.mark.xfail
xfail可以拆分成x和fail理解,x表示可以预期到的结果,fail为失败,合起来可以表达成可以预期到的失败的测试。xfail装饰器解决的是对于很清楚的知道他的记过是失败的,但是又不想直接跳过的测试方法,通过添加xfail装饰器可以在结果中给出明显的标识
新建一个test_xfail.py

import pytest
"""
# 源码
def __call__(
self,
condition: str | bool = False, # 主要条件参数,可以是字符串或布尔值,默认值为 False
*conditions: str | bool, # 可变参数,允许传递多个条件,每个条件可以是字符串或布尔值
reason: str = ..., # 字符串参数,用于说明标记的原因,默认值为未指定
run: bool = ..., # 布尔值参数,用于控制是否运行测试,默认值为未指定
raises: None | type[BaseException] | tuple[type[BaseException], ...] = ..., # 异常类型参数,用于指定测试是否应该抛出特定异常,默认值为未指定
strict: bool = ..., # 布尔值参数,用于控制是否严格匹配异常,默认值为未指定
) -> MarkDecorator: # 返回一个 MarkDecorator 对象,用于标记测试
这是一个特殊方法 __call__,用于定义对象被调用时的行为。
在 pytest 中,它被用于实现标记装饰器(MarkDecorator)的功能。
参数说明:
- condition: 主要条件参数,可以是字符串或布尔值。如果条件为 True 或非空字符串,标记会生效。
- *conditions: 可变参数,允许传递多个条件。所有条件会被组合起来,决定标记是否生效。
- reason: 字符串参数,用于说明标记的原因。例如,跳过一个测试时,可以提供一个跳过的原因。
- run: 布尔值参数,用于控制是否运行测试。如果为 False,测试会被跳过。
- raises: 异常类型参数,用于指定测试是否应该抛出特定异常。如果测试没有抛出指定异常,测试会失败。
- strict: 布尔值参数,用于控制是否严格匹配异常。如果为 True,测试抛出的异常必须完全匹配 raises 参数指定的异常类型。
返回值:
- 返回一个 MarkDecorator 对象,用于标记测试。
"""
@pytest.mark.xfail()
def test_xfail1():
assert 11 + 1 == 12
@pytest.mark.xfail(reason="运算错误")
def test_xfail2():
assert 5 + 5 == 11
# condition为True, 一定要加上reason
# strict 参数用于控制是否将 XPASS 视为失败。如果 strict=True,XPASS 会被视为失败
@pytest.mark.xfail(strict=True)
def test_xfail3():
assert 1 + 1 == 2
strict为True

@pytest.mark.patametrize
使用pytest -k 测试方法名 只运行该测试方法
代码:
单个参数
# parametrize 用于对测试方法进行数据参数化,使得同一个测试方法结合
# 不同的测试数据也可以达到同时测试的目的
import pytest
list_one = [1, 2, 3, 4]
"""
1. 如果argnames只有一个名称, 则argvalues要以列表的形式给出值
2. 如果argnames有多个名称,则argvalues需要以列表嵌套元组的形式给出值
3. 如果parametrize的参数名称和fixture一样,会覆盖掉fixture
e.g:
@parametrize('arg1',[1,2]) 将对测试函数调用两次
...第一次调用arg1=1, 第二次调用arg1=2
@parametrize('arg1','arg2',[(1,2),(3,4)] 将对测试函数调用两次
...第一次调用: arg1=1, arg2=2 第二次调用arg1=3, arg2=4
"""
@pytest.mark.parametrize('number', list_one)
def test_parametrize1(number):
assert number in list_one

多个参数
# 多个参数
list_two = [(1, 2, 3), (2, 3, 4), (3, 4, 7)]
@pytest.mark.parametrize('num1,num2,sum', list_two)
def test_parametrize2(num1, num2, sum):
assert num1 + num2 == sum

直接标记
mark标记是通过在测试方法上添加装饰器进行标记,还有一种标记方法是在命令行中使用参数进行标记
使用参数进行标记的方法有两种:
-
第一种是直接标记:只运行某个固定的py文件,或在py文件后添加双引号::运行固定的测试方法
-
通过参数-k进行模糊匹配标记
-
pytest test.example.py 只运行这个py文件
添加双引号,只运行这一个方法
pytest test.example.py::test_add

也可以执行多个方法

模糊匹配标记
在直接标价中一次只能执行一个测试文件或者方法,如果一次执行多个测试方法可以使用模糊匹配标记,模糊匹配使用起来很简单:
pytest -k 命令 进行匹配标记即可
pytest -v -k 信息更详细一些

使用mark自定义标记
我们根据mark进行自定义标记,只需在测试方法前添加装饰器 pytest.mark.标记名
标记名建议根据项目取比较容易世标的词,例如:commit, mergerd, done, undo等
在命令模式下使用时:只需要通过参数 -m 加上标记名就可执行被标记的测试方法
创建一个test_customize.py
import pytest
def add_number(a, b):
return a + b
@pytest.mark.done
def test_add1():
assert add_number(2, 3) == 5
@pytest.mark.undo
def test_add2():
assert add_number(2, 3) == 4
@pytest.mark.undo
def test_add3():
assert add_number(3, 3) == 6

pytest在执行通过 -m 参数只执行被done标记的测试方法,使用命令 pytest -v -m 'done'
第三章 固件Fixture
简介:
Fixture 中文称为固件或者夹具,用于测试用例执行前的数据准备、环境搭建和测试用例执行后的数据销毁、环境恢复等工作,与单元测试框架UnitTest中的setup、teardown功能类似,但是pytest框架提供的fixture更灵活,不但允许代码在运行时旨在某些特定测试用例前执行,而且还可以在测试用例和测试用例之间传递参数和数据
fixture的使用
如果要将一个方法作为fixture使用,只需要在该方法前添加装饰器@pytest.fixture()即可
import pytest
@pytest.fixture()
def fixture_prepare():
print("\nthis is fixture prepare")
def test_fixture1(fixture_prepare):
print('test_fixture1')
def test_fixture2(fixture_prepare):
print('test_fixture2')
if __name__=='__main__':
pytest.main(['-s','test.fixture.py'])
执行结果:可以看到每一个case执行之前都执行了fixture_prepare
fixture参数
- scope:定义fixture的作用域,有4组可选参数:function,class, module,package/session,默认为function
- params:一个可选的参数列表,会使多个参数调用fixture函数和所有测试使用它
- autouse:如果为True,则所有方法都会执行固件方法,如果为False(默认值),则支队天界了固件方法的测试方法执行固件方法
- ids:每个参数都与列表中的字符串id对应,因此他们是测试id的一部分,如果没有提供id将会从参数中自动生成
- name: Fixture的名称,默认为装饰器的名称,如果Fixture在与他定义的模块中使用,那么这个fixture的功能名称将被请求的fixture功能参数遮盖。可以用该国将装饰函数命名为"fixture_fixturename" 然后使用"@pytest.fixture(name='fixturename')解决这个问题
fixture的作用域
fixture的作用域用来指定固件使用的范围,固件的使用范围可以通过scope参数进行声明
function:函数级别,默认级别,每个测试方法执行前都会执行一次
class:类界别,每个测试类执行前执行一次
module:模块级别,每个模块执行前执行一次,也就是每个.py文件执行前都会执行一次
session:会话级别,一次测试只执行一次,即多个文件调用一次,可以跨.py文件
import pytest
@pytest.fixture(scope='session')
def sesseion_fixture():
pass
@pytest.fixture(scope='module')
def module_fixture():
pass
@pytest.fixture(scope='class')
def class_fixture():
pass
@pytest.fixture(scope='function')
def function_fixture():
pass
def test_fixture(sesseion_fixture, module_fixture, class_fixture, function_fixture):
pass
if __name__ == '__main__':
pytest.main(['--setup-show', 'fixture_scope.py'])
命令:
pytest --setup-show fixture_scope.py

使用参数 --setup-show(查看具体的setup和teardown)顺序,从图中可以看到明显的作用域表示符号
S:session会话级别
M:module
C:class级别
F:function函数级别
@pytest.mark.usefixtures()
当用例需要调用fixture时,可以用过直接在用例里加fixture参数,如果一个测试class类中所有的测试方法都需要用到fixture,美分用例都去传参会比较麻烦,这个时候选择在class类上使用装饰器,@pytest.mark.usefixtures修饰,使整个class都调用Fixture
在运行 pytest
时,添加 -s
选项以显示 print
语句的输出:
import pytest
from fixture_scope import function_fixture
@pytest.mark.usefixtures('function_fixture')
class TestFixture:
def test_fixture1(self):
pass
def test_fixture2(self):
pass
注意:Fixture有返回值,而usefixtures无法获取到返回值,则不再适用
执行结果

autouse(自动使用)
我们可以看到测试方法通过参数名称可以使用测试固件,但是当测试方法特别多时,每次传入参数特别麻烦,为了解决这一问题,Fixture提供了autouse,可以自动将测试固件添加到测试方法上。autouse默认是False, 不启用,如果设置为True,则开启自动使用Fixture功能,着用就不需要每次必须传入参数,即可使用测试固件
import pytest
@pytest.fixture(autouse=True)
def autouse_fixture():
print('this is autouse of fixture')
def test_fixture1():
print('this is test_fixture1')
def test_fixture2():
print('this is test_fixture2')
if __name__ == '__main__':
pytest.main(['-s', '--setup-show', 'fixture_autouse.py'])

运行结果可以看出:
test_fixture1和test_fixture2两个测试方法的setup和teardown都执行连固件autouse_fixture,与预期结果一致,可见autouse可以自动将测试固件添加到测试方法上
注意:测试固件旨在测试方法 前 进行内容输出
yeild的使用
在UnitTest单元测试框架中,有setup和teardown功能作为数据的准备和销毁,但是autouse的示例中知道,测试固件只在测试方法运行前进行内容输出
而在测试方法完成之后没有任何输出.
如果想在测试结束后执行操作,需要使用yield的配合,如果没有yield就相当于只有setup,没有teardown
import pytest
@pytest.fixture()
def fixture_yield():
print('\nTest started----------我是setup')
yield
print('\nEnd of test------------我是teardown')
def test_yield(fixture_yield):
print('\n数据销毁测试')
运行命令: pytest -s --setup-show test_yield.py

可以看出:测试用例在执行前执行连yield关键词之前的语句,测试用例执行后执行了yield关键词之后的语句
注意点:
共享Fixture功能
许多测试用例的前置条件都存在相同的内容,比如一个后台管理系统的测试,登录是绕不过去的,如果每一个测试用例都要复写一边登录显然不合理。因此将登录写成一个方法,然后共享给所有需要使用的测试用例即可达到服用的目的;在pytest框架下提供了一个共享fixture的功能
只需要创建一个名为conftest.py的文件,将共享的功能在里面定义,其他测试文件在运行时会自动查找
在使用conftest.py文件时的注意点:
- conftest.py文件名称需要固定,不能更改
- conftest.py需要与运行的用例文件在同一个package下,并且存在__init__.py文件
- 使用conftest.py时不需要import导入,pytest用例会自动识别
- 如果conftest.py放在项目的根目录下,则对全局生效。如果放在某个package下,则只对package下的用例文件神效,允许存在多个conftest.py文件
- conftest.py文件不能被其他文件导入
- 所有同目录测试文件运行前都会执行conftest.py文件
创建文件:FileConftest

# 定义一个登录退出功能,在测试方法运行前进行登录,测试方法结束后退出登录
# 并且给登录退出方法加上Fixture装饰器@pytest.fixture
import pytest
@pytest.fixture()
def signin_signout():
print('\n成功登陆到系统') #setup
yield
print('\n退出系统') #teardown
test_file1:
import pytest
def test_conftest1(signin_signout):
print("第一个测试方法进行操作")
test_file2:
import pytest
def test_conftest2(signin_signout):
print("第2个测试方法进行操作")
def test_conftest3(signin_signout):
print("第3个测试方法进行操作")
在命令行模式下进入FileConftest目录,使用pytest -v -s运行脚本,在控制台输出测试结果

conftest.py的登录退出的作用域是函数级别的,所以程序运行中每个测试方法都会执行
如果想过要登录退出功能在程序运行过程中只运行一次,那么只需要将Fixture的作用域改成session
参数化
在mark标记中已经了解到可以用@pytest.mark.parametrize对测试方法进行参数化,那么在固件中也可以同样对其进行参数化,因为固件Fixture也是函数。与pytest.mark.parametrize不同的是,Fixture参数化是通过参数params实现的
同一个测试方法可能需要不同的参数来构造逻辑基本相同,环境或者结果稍微有所不同的场景,这时候可以利用Fixture的参数化([arametrizing)来减少重复工作。例如测试两个数的和的一个测试方法,则可使用参数化进行测试
import pytest
# params: Iterable[object] | None = None,
@pytest.fixture(params=[(1, 3, 4), (2, 4, 6), (12, 33, 45)])
def test_params(request):
print(request)
return request.param
def test_add(test_params):
assert test_params[2] == test_params[0]+test_params[1]
执行固件参数化会使用pytest中内置的固件request,并通过request.param来获取参数,代码结束后,可以看到运行了3次,有3组测试数据

内置Fixture
如果有空会继续更新,感谢你的支持~
后续是:
pytest插件
插件的安装和卸载
查看活动插件
插件的注销
allure测试报告
allure的安装
脚本应用
报告生成
总结
路漫漫其修远兮,后续更新自动化项目实战,一些列子