全网最全Pytest框架使用教程和项目实战~从入门到精通!!!

一、Pytest简介1.1 pytest介绍1.2、Pytest默认规则

二、 Pytest测试用例执行方式2.1 主函数模式2.2 命令行模式2.3 参数详解2.4 通过读取pytest.ini配置文件运行(重点)

三、Pytest执行顺序四、如何分组执行五、Pytest跳过用例5.1 无条件跳过5.2 有条件跳过

六、前后置(夹具、固件)6.1 setup/teardown,setup_class/teardown_class实现前后置6.2 使用@pytest.fixture()装饰器来实现用例的前后置6.3 通过conftest.py和@pytest.fixture()结合使用实现全局的前后置应用

七、pytest结合allure-pytest插件生成allure测试报告7.1 allure环境搭建7.2 生成allure测试报告实例

八、@pytest.mark.parametrize---参数化九、YAML文件详解--实现接口自动化9.1 YAML介绍9.2 YAML编写测试用例常用关键字9.3 示例

一、Pytest简介

1.1 pytest介绍

pytest是一个非常成熟的python单元测试框架,比unittest更灵活、更容易上手pytest可以和selenium、requests、appinum结合实现web自动化、接口自动化、app自动化pytest可以是实现测试用例的跳过以及reruns失败用例重试pytest可以和aliure生成非常美观的测试报告pytest可以和jenkins持续集成pytest有非常强大的插件,并且这些插件能够实现很多的使用的操作

#常用安装插件

pytest

pytest-html (生成html格式的自动化测试报告)

pytest-xdist (测试用例分布式执行,多cpu分发)

pytest-ordering(用于改变测试用例的执行顺序)

allure-pytest(用于生成美观的测试报告)

pytest-rerunfailures(用例失败后重跑)

一般项目作者会把依赖文件附到项目中一起上传,将这个文件移动到venv文件夹中,打开pycharm中的命令行,这里注意,要在命令行里激活当前的虚拟环境,用的pip才是这个环境的,pip才会把依赖包下载到这个虚拟环境里。激活虚拟环境的方法是cd到venv\Scripts文件夹,输入activate.bat命令进入虚拟环境后,cd …退出到venv文件夹(这里放着requirements.txt),然后输入以下指令:pip install -r requirements.txt等待安装即可,安装的依赖包位置在:项目路径\venv\Lib\site-packages

1.2、Pytest默认规则

1、模块名必须以test_开头或者_test结尾 2、测试类必须以Test开头,并且不能有__init__方法 3、测试方法必须以test开头

二、 Pytest测试用例执行方式

2.1 主函数模式

1、运行所有:pytest.main() 2、指定模块:pytest.main([‘-vs’,‘test_login.py’]) 3、指定目录:pytest.main([“-vs”,“testcase”]) 4、通过nodeid指定用例运行:nodeid由模块名,分隔符,类名,方法名,函数名组成 pytest.main([“-vs”,“./interface_testcase/test_interface.py::Testinterface::test_03_zhiliao”])

'''

前置条件:

在test_login.py下创建两条测试用例

在test_pass.py下创建两条测试用例

一共4条测试用例

'''

import pytest

class TestLogin:

def test_01(self):

print("测试")

if __name__ == '__main__':

pytest.main(["-vs"])

# pytest.main(["-vs"]) 将会执行所有的测试用例,4条测试用例都会执行

#pytest.main(["-vs","./test_login.py"] 只会执行test_login.py下的两条测试用例

2.2 命令行模式

1、运行所有:pytest 指定模块:pytest -vs 2、test_login.py 指定目录:pytest -vs ./interface_testcase 3、指定nodeid:pytest -vs ./interface_testcase/test_interface.py::Testinterface::test_03_zhiliao

2.3 参数详解

-s:表示输出调试信息,包括print打印的信息

-v:显示详细信息

-vs:一般这两个参数一起使用

-n:支持多线程或分布式运行测试用例

例如:pytest -vs ./testcase/test_login.py -n 2

例如:pytest.main(["-vs", "./test_login.py", "-n=2"])

--return:失败用例重跑

-x:表示只要一个用例报错,就停止测试

--maxfail=2:出现两个用例失败就停止

-k:根据测试用例的部分字符串指定测试用例

例如:pytest -vs -k "te"

2.4 通过读取pytest.ini配置文件运行(重点)

pytest.ini这个文件它是pytest单元测试框架的核心配置文件 1、位置:一般放在项目的根目录 2、编码:必须是ANSI,可以使用notepad++修改编码格式 3、作用:改变pytest默认的行为 4、 运行的规则:不管是主函数模式,还是命令行模式,都会读取这个配置文件

#文件名pytest.ini

[pytest]

#命令行参数,用空格分割

addopts = -vs

#测试用例文件夹,可自己配置

testpaths = ./testcase

#配置测试搜索的模块文件名称

python_files = test*.py

#配置测试搜索的测试类名

python_classes = Test*

#配置测试搜索的测试函数名

python_functions = test

三、Pytest执行顺序

unittest执行顺序:按照ascli的大小来执行 pytest执行顺序:默认从上到下执行

改变pytest的默认执行顺序:使用@pytest.mark.run(order=1)

'''

需求:将test_02第一个先执行

'''

import pytest

class TestLogin:

def test_01(self):

print("测试-1")

@pytest.mark.run(order=1) #.run(order=1) 要手动敲不会自动补全

def test_02(self):

print("测试-2")

四、如何分组执行

我们在测试过程中经常会有冒烟测试、分模块测试、分接口测试和web测试等等,那么如何使用pytest进行分组执行测试?

在pytest.ini文件中添加markers字段

[pytest]

addopts = -vs

testpaths = ./testcase

python_files = test*.py

python_classes = Test*

python_functions = test

markers =

smoke:冒烟用例

usermanage:用户管理模块

productmangage:商品管理模块

五、Pytest跳过用例

5.1 无条件跳过

无条件跳过: @pytest.mark.skip(reason"跳过")

import pytest

class TestLogin:

@pytest.mark.usermanage

@pytest.mark.skip(reason="跳过")

def test_01(self):

print("测试-1")

@pytest.mark.run(order=1)

@pytest.mark.smoke

def test_02(self):

print("测试-2")

#执行结果:

testcase/test_login.py::TestLogin::test_01 SKIPPED (跳过)

5.2 有条件跳过

有条件跳过: @pytest.mark.skipif(age=18,reason=“年龄等于18则跳过”)

import pytest

class TestLogin:

age = 18

@pytest.mark.usermanage

@pytest.mark.skip(reason="跳过")

def test_01(self):

print("测试-1")

@pytest.mark.skipif(age=18,reason="年龄等于18则跳过")

@pytest.mark.run(order=1)

@pytest.mark.smoke

def test_02(self):

print("测试-2")

#执行结果

testcase/test_login.py::TestLogin::test_02 SKIPPED (年龄等于18则跳过)

interfacecase/test_inter.py::TestPass::test_05 测试-5

PASSED

interfacecase/test_inter.py::TestPass::test_06 测试-6

PASSED

testcase/test_login.py::TestLogin::test_01 SKIPPED (跳过)

testcase/test_pass.py::TestPass::test_03 测试-3

PASSED

testcase/test_pass.py::TestPass::test_04 测试-4

PASSED

======================== 4 passed, 2 skipped in 0.03s =========================

六、前后置(夹具、固件)

6.1 setup/teardown,setup_class/teardown_class实现前后置

为什么要使用前后置? 比如:web自动化执行用例之前,请问需要打开浏览器嘛?用例执行后需要关闭浏览器嘛?

用法: def setup(self):和def teardown(self): 在每个用例执行前后执行一次。 def setup_class(self): 和def teardown_class(self): 在当前类的所有用例执行前后执行一次

class TestWeb:

#这个在所有的用例之前只执行一次

def setup_class(self):

print('在每个类执行前的初始化的工作:比如:创建日志对象,创建数据库的连接,创建接口的请求对象。')

#在每个用例之前执行一次。

def setup(self):

print('\n在执行测试用例之前初始化的代码:打开浏览器,加载网页')

def test_01_baili(self):

print('测试-01')

def test_02_xingyao(self):

print('测试-02')

def teardown(self):

print('\n在执行测试用例之后的扫尾的代码:关闭浏览器')

def teardown_class(self):

print('在每个类执行后的扫尾的工作:比如:销毁日志对象,销毁数据库的连接,销毁接口的请求对象。')

6.2 使用@pytest.fixture()装饰器来实现用例的前后置

@pytest.fixture(scope="",params="",autouse="",ids="",name="")

--------------------------------------------------------------------------------

scope:表示的是被@pytest.fixture标记的方法的作用域。function(默认),class,module, package/session

params:参数化

autouse:默认False autouser=Ture 自动执行

ids:当使用params参数化时,给每一个值设置一个变量,意义不大

name:表示的是被@pytest.fixture标记的方法取一个别名

import pytest

class TestLogin:

age = 18

#部分用例前置,后置,yield表示后置

@pytest.fixture()

def my_fixtre(self):

print("前置")

yield

print("后置")

#将my_fixture函数传入,将此用例进行前后置

def test_01(self,my_fixtre):

print("测试-1")

def test_02(self):

print("测试-2")

执行结果:

test_login.py::TestLogin::test_02 测试-2

PASSED

test_login.py::TestLogin::test_01 前置

测试-1

PASSED后置

参数化:(一般不用,了解)

注:写在最外层,不在类中填写,函数名中传入request是注定写法,request.param 返回参数也是固定写法

import pytest

@pytest.fixture(scope="function", params=["成龙", "甄子丹", "蔡依林"])

#函数名中传入request是注定写法,request.param 返回参数也是固定写法

def my_fixtre(request):

yield request.param #retuen和yield都表示返回的意思,但是yield后面可以跟代码

print("前置")

class TestLogin:

age = 18

@pytest.mark.usermanage

def test_01(self,my_fixtre):

print("测试-1")

print(my_fixtre)

@pytest.mark.run(order=1)

@pytest.mark.smoke

def test_02(self):

print("测试-2")

#执行结果:

test_login.py::TestLogin::test_02 测试-2

PASSED

test_login.py::TestLogin::test_01[\u6210\u9f99] 测试-1

成龙

PASSED前置

test_login.py::TestLogin::test_01[\u7504\u5b50\u4e39] 测试-1

甄子丹

PASSED前置

test_login.py::TestLogin::test_01[\u8521\u4f9d\u6797] 测试-1

蔡依林

PASSED前置

test_pass.py::TestPass::test_03 测试-3

PASSED

test_pass.py::TestPass::test_04 测试-4

PASSED

6.3 通过conftest.py和@pytest.fixture()结合使用实现全局的前后置应用

使用规则:

conftest.py文件是单独存放的一个夹具配置文件,名称不能更改用处可以在不同的py文件中使用同一个fixture函数原则上conftest.py需要和运行的测试用例放到同一层级,并且不需要做任何的import导入的操作

全局的conftest.py文件,在最外层 内部的conftest.py文件 用例调用

执行结果:

testcase/test_login.py::TestLogin::test_02 测试-2

PASSED

testcase/test_login.py::TestLogin::test_01[\u4ed8\u4f1f\u6770-\u6210\u9f99] 测试-1

付伟杰

成龙

PASSED全局前置

用户管理前置

testcase/test_login.py::TestLogin::test_01[\u4ed8\u4f1f\u6770-\u7504\u5b50\u4e39] 测试-1

付伟杰

甄子丹

PASSED全局前置

用户管理前置

testcase/test_login.py::TestLogin::test_01[\u4ed8\u4f1f\u6770-\u8521\u4f9d\u6797] 测试-1

付伟杰

蔡依林

PASSED全局前置

用户管理前置

testcase/test_login.py::TestLogin::test_01[\u5c0f\u5218-\u6210\u9f99] 测试-1

小刘

成龙

PASSED全局前置

用户管理前置

testcase/test_login.py::TestLogin::test_01[\u5c0f\u5218-\u7504\u5b50\u4e39] 测试-1

小刘

甄子丹

PASSED全局前置

用户管理前置

testcase/test_login.py::TestLogin::test_01[\u5c0f\u5218-\u8521\u4f9d\u6797] 测试-1

小刘

蔡依林

PASSED全局前置

用户管理前置

testcase/test_login.py::TestLogin::test_01[\u5c0f\u5b5f-\u6210\u9f99] 测试-1

小孟

成龙

PASSED全局前置

用户管理前置

testcase/test_login.py::TestLogin::test_01[\u5c0f\u5b5f-\u7504\u5b50\u4e39] 测试-1

小孟

甄子丹

PASSED全局前置

用户管理前置

testcase/test_login.py::TestLogin::test_01[\u5c0f\u5b5f-\u8521\u4f9d\u6797] 测试-1

小孟

蔡依林

PASSED全局前置

用户管理前置

================================================================= 10 passed in 0.04s =================================================================

七、pytest结合allure-pytest插件生成allure测试报告

7.1 allure环境搭建

7.2 生成allure测试报告实例

import os

import pytest

class TestApi:

def test_01(self):

print("测试-1")

def test_02(self):

print("测试-2")

if __name__ == '__main__':

pytest.main(['-vs', '--alluredir', './tmp'])

os.system('allure generate ./tmp -o ./report --clean')

八、@pytest.mark.parametrize—参数化

@pytest.mark.parametrize(args_name,args_value)

args_name:参数名

args_value:参数值(列表,元祖,字典列表,字典元祖) 有多少个值用例就会执行多少次

import pytest

class TestLogin:

age = 18

@pytest.mark.parametrize("args", ["老付", "小刘", "小孟"])

def test_01(self, args):

print("测试-1")

print(args)

def test_02(self):

print("测试-2")

if __name__ == '__main__':

pytest.main()

#执行结果

test_login.py::TestLogin::test_01[\u8001\u4ed8] 测试-1

老付

PASSED

test_login.py::TestLogin::test_01[\u5c0f\u5218] 测试-1

小刘

PASSED

test_login.py::TestLogin::test_01[\u5c0f\u5b5f] 测试-1

小孟

PASSED

test_login.py::TestLogin::test_02 测试-2

PASSED

九、YAML文件详解–实现接口自动化

9.1 YAML介绍

9.2 YAML编写测试用例常用关键字

feature: 模块名(必填)

story: 接口名(必填)

title: 用例标题(必填)

request:请求(必填)

method:请求方法(必填)

url:请求路径(必填)

headers:请求头

params:url之后的参数

data:表单数据

json:json数据

files:文件上传

extract:

access_token: $.access_token 接口关联提取

vaildate:断言(必填)

codes:断言状态码

equals:相等断言

contains:包含断言

db_equals: 数据断言

9.3 示例

#test_api.yaml文件-

name: 获取token鉴权码的接口

request:

url: https://www.baidu.com/

method: get

headers:

Content-type: application/json

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36

vaildate:

eq: 200

#yaml.util.py文件

import yaml

class YamlApi:

def __init__(self, yaml_file):

"""

通过init方法把yaml文件传入到这个类

:param yaml_file: yaml文件路径

"""

self.yaml_file = yaml_file

def write_yaml(self):

"""

读取yaml,对yaml反序列化,就是把我们的yamk格式转成dict格式

:return:

"""

with open(self.yaml_file, encoding="utf-8") as f:

value = yaml.load(f, Loader=yaml.FullLoader)

print(value, type(value))

return value

if __name__ == '__main__':

YamlApi("./test_api.yaml").write_yaml()

#test_api.py 文件

import pytest

import requests

from testcase.yaml_util import YamlApi

class TestApi:

@pytest.mark.parametrize("args", YamlApi("./test_api.yaml").write_yaml())

def test_10_baidu(self, args):

print(args)

url = args["request"]["url"]

code = args["vaildate"]["eq"]

res = requests.get(url)

code1 = res.status_code

print(code1)

assert code == code1

if __name__ == '__main__':

pytest.main(["-vs", "./test_api.py"])

# 执行结果

test_api.py::TestApi::test_10_baidu[args0] PASSED

============================== 1 passed in 0.46s ==============================

精彩链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: