pytest框架使用

一、需要安装插件

pip install pytest
pip install pytest-xdist
pip install pytest-ordering
pip install pytest-rerunfailures
pip install pytest-html
pip install allure-pytest

二、注意事项

  1. 文件名必须以test_开头或以_test结尾 (.py文件)
  2. 测试类必须以Test开头,并且不能有__init__方法(class 定义的类名)
  3. 测试方法必须以test开头 (def 定义的函数名)
  4. 默认从当前目录下收集测试用例,当配置testpath时,从配置的路径下手机测试用例
    ps:修改配置文件后,模块名、测试类、测试方法应该与配置文件一致

三、使用

1、测试用例

1、创建测试

# 测试函数
def test_demo1():
    print('test_01')

# 测试类
class Test_demo01():
    def test_01(self):
        # 正常
        assert 1==1

    def test_02(self):
        # 错误示例
        assert 1==2

2、运行测试用例

1、通过pytest命令执行测试用例

在这里插入图片描述

# 不会控制台打印print语句
pytest
#  打印print语句
pytest -s
#  指定文件执行
pytest -vs test_demo01.py test_demo02.py
# 指定运行目录
pytest -vs .\testdemo\  # testdemo是模块

2、通过Python代码执行(主函数)

import pytest
if __name__ == '__main__':
    pytest.main(['-vs','../testdemo/test_demo01.py','../testdemo/test_demo02.py']) 

3、参数详解

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

import pytest
if __name__ == '__main__':
    pytest.main(['-s']) #主函数模式
​
pytest -s #命令行模式

-v:显示更详细的信息

import pytest
if __name__ == '__main__':
    pytest.main(['-v']) #主函数模式
​
pytest -v #命令行模式

-vs:v和s两个参数一起用

import pytest
if __name__ == '__main__':
    pytest.main(['-vs']) #主函数模式
​
pytest -vs #命令行模式

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

import pytest
if __name__ == '__main__':
    pytest.main(['-vs','-n=2']) #主函数模式
​
pytest -vs -n 2  #命令行模式

–reruns NUM:失败用例重跑,NUM为重跑次数

import pytest
if __name__ == '__main__':
    pytest.main(['-vs','--reruns=2']) #主函数模式
​
pytest --reruns 2 #命令行模式

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

import pytest
if __name__ == '__main__':
    pytest.main(['-vs','-x']) #主函数模式
​
pytest -x #命令行模式

–mainfaill=2 :出现两个用例失败就停止

import pytest
if __name__ == '__main__':
    pytest.main(['-vs','--maxfail=2'])#主函数模式
​
pytest --maxfail 2 #命令行模式

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

import pytest
if __name__ == '__main__':
    pytest.main(['-vs','-k=baili'])#主函数模式,若函数名包含baili则执行该用例
    
import pytest
if __name__ == '__main__':
    pytest.main(['-vs','-k=not baili'])#主函数模式,若函数名包含baili则执行该用例    
  
​
pytest -k 'baili'#命令行模式
pytest -k 'not baili'#命令行模式,不包含baili则执行

–html ./report/report.html:生成html的测试报告
在项目根目录下新建一个report包用于存储报告

import pytest
if __name__ == '__main__':
    pytest.main(['-vs','--html=./report/report.html'])  #主函数模式#命令行模式
pytest --html ./report/report.html

4、执行顺序

在模块级别采用模块名的ascii码顺序,在模块内部根据从上往下的定义顺序来执行。

可使用mark标记改变pytest默认的执行顺序

class TestInterface:
    def test_03_interface(self):
        print('test03')@pytest.mark.run(order=2) #定义运行顺序
    def test_05_interface(self):
        print('test-05')@pytest.mark.run(order=1) #定义运行顺序
    def test_06_interface(self):
        print('test-06')def test_07_interface(self):
        print('test-07')
#执行顺序为6-5-3-7

3、断言

在pytest中只需使用python语言标准的断言语句 assert 来断言。

4、前后置断言

1、经典的xunit风格

xunit是一种经典且流行的方式,该方式可以基于模块/类/函数实现固定装置(设置和拆卸测试状态)

  1. 模块级别的setup_module和teardown_module:
    在整个模块调用前后执行一次:
def setup_module():
    '''
    模块级前置条件
    :return:
    '''
    print('我会在当前模块所有测试执行之前执行')def teardown_module():
    '''
    模块级后置条件
    :return:
    '''
    print('我会在当前模块所有测试执行之后执行')def test_01():
    print('sede')
class TestHaha():
    def test_01(self):
        print(234)
    def test_02(self):
        print(456)
  1. 类级别setup_class和teardown_class
    在整个类调用前后执行一次:
class TestHaha():@classmethod
    def setup_class(cls):
        '''
        类级前置条件
        :return:
        '''
        print('我会在当前类所有测试执行之前执行')@classmethod
    def teardown_class(cls):
        '''
        类级后置条件
        :return:
        '''
        print('我会在当前类所有测试执行之后执行')
    def test_01(self):
        print(234)
    def test_02(self):
        print(456)
  1. 方法级别setup_method和teardown_method
    在整个方法调用前后执行一次:
class TestHaha():@classmethod
    def setup_method(self):
        '''
        方法级前置条件
        :return:
        '''
        print('我会在当前类里每个测试方法执行之前执行')@classmethod
    def teardown_method(self):
        '''
        方法级后置条件
        :return:
        '''
        print('我会在当前类类每个测试方法执行之后执行')def test_01(self):
        print(234)def test_02(self):
        print(456)
  1. 方法级别setup_function和teardown_function
    在模块每个函数调用前后执行一次:
def setup_function():
    '''
    函数级别的前置
    :return:
    '''
    print('我会在当前模块在每个测试函数执行之前执行')def teardown_function():
    '''
    函数级别的后置
    :return:
    '''
    print('我会在当前模块在每个测试函数执行之后执行')def test_01():
    print('sede')
​
​
def test_02():
    print('sdjf')

2、unittest风格

pytest支持unittest的夹具风格(可通过pytest的执行方式执行)

import unittest
​
class TestMay(unittest.TestCase):@classmethod
    def setUpClass(cls) -> None:
        '''
        类前置条件
        :return:
        '''
        print('我会在当前类所有测试执行之前执行')@classmethod
    def tearDownClass(cls) -> None:
        '''
        类后置条件
        :return:
        '''
        print('我会在当前类所有测试执行之后执行')def setUp(self) -> None:
        '''
        方法前置条件
        :return:
        '''
        print('会在当前类里所有方法测试执行之前执行')def tearDown(self) -> None:
        '''
        方法后置条件
        :return:
        '''
        print('会在当前类里所有方法测试执行之后执行')def test_one(self):
        print('test')
        self.assertEqual(1,1)def test_two(self):
        print('cde')

3、@pytest.fixture

pytest框架有一种通过装饰器实现的夹具机制

1. 定义:通过@pytest.fixture可以定义夹具
import pytest

@pytest.fixture
def fixture_func():   # 不能随便接受参数
    print('pytest.fixture的一个前置条件')
    yield '托尔斯泰'  #yield所在行为返回值,yield上面的代码都是前置,后面的代码都是后置
    print('pytest.fixture的一个后置条件')

2. 调用夹具:
  1. 通过装饰@pytest.mark.usefixtures(‘fixture_func’)
# 使用装饰器语法调用夹具# 修饰函数
@pytest.mark.usefixtures('fixture_func')
def test_function():
    print('我是一个测试函数')# 修饰整个类
@pytest.mark.usefixtures('fixture_func')
class TestSome():def test_one(self):
        print('one')def test_two(self):
        print('two')
  1. 通过在测试函数中定义与夹具函数名同名的参数
# 使用装饰器语法调用夹具
@pytest.mark.usefixtures('fixture_func')
def test_function():
    print('我是一个测试函数')

这种方式还可以接收夹具的返回值(夹具的返回值定义在yield所在行)

import pytest
​
@pytest.fixture
def fixture_func():   # 不能随便接受参数
    print('pytest.fixture的一个前置条件')
    yield   'test' #test为夹具的返回值
    print('pytest.fixture的一个后置条件')
​
​
# 使用函数传参的方法来调用前置后置
def test_two(fixture_func):
    print(fixture_func) #通过函数名调用夹具的返回值
    print(12345)# 在类中使用夹具返回值
class TestSome():def test_one(self,fixture_func):
        print('one')def test_two(self):
        print('two')
@pytest.fixture
def db():
    import pymysql
    with pymysql.connnect() as conn:
        yield conn   #conn为yield返回值
        
        
@pytest.mark.usefixtures("fixture_func")
def testa(db):
    cursor = db.cursor()   #通过函数名调用夹具的返回值
    cursor.execute('select * from student')
    assert cursor.fetch_one()
3.夹具的作用范围

通过@pytest.fixture装饰器的参数scope可以指定夹具的作用范围

  • function 默认范围,函数范围,在测试完成后结束
  • class 在类中最后一共测试完成后结束
  • module 在模块中最后一个测试完成后结束
  • package 在包中的最后一个测试完成后结束
  • session 在一次会话中的最后一共测试完成后结束

修饰类:

import pytest
​
@pytest.mark.usefixtures('class_fixture')
class TestSome():def test_one(self):
        print('one')def test_two(self):
        print('two')# 如果使用scope='class'修饰类,在整个类执行前开始,在整个类所有测试执行完之后结束        
@pytest.fixture(scope='class')
def class_fixture(self):
    print('我是一个类级前置')
    yield
    print('我是一个类级后置')
    
   
# 其他scope参数值作用范围同理

修饰模块:

# 模块级前后置,传入参数autouse=True运行时自动调用@pytest.fixture(scope='module',autouse=True)
def moudle_fixture():
    print('我是一个模块级前置')
    yield
    print('我是一个模块级后置')

修饰包:
在测试用例包下新建conftest.py,内容如下:

import pytest
​
# 设置autouse=True,当pytest执行整个测试用例包内容时,自动执行
@pytest.fixture(scope='package',autouse=True)
def package_fixture():
    print('我在整个包测试开始之前执行')
    yield
    print('我在整个包测试执行完成之后执行')

修饰会话:
在测试用例包下新建conftest.py,内容如下:

import pytest
​
# 设置autouse=True,当pytest执行整个测试用例包内容时,自动执行
@pytest.fixture(scope='session',autouse=True)
def package_fixture():
    print('我在整个测试执行前执行')
    yield
    print('我在整个测试执行后执行')
4.共享夹具

如果一个夹具需要被多个文件使用,则将其定义在conftest.py文件中,通过函数名调用,不需要在测试中倒入,pytest框架会自动发现并执行。

在同一目录下,新增conftest.py和test_01.py文件(在执行时先在当前目录下查找conftest.py中内容,若不存在则查找上层目录、上上层中conftest.py,若不存在,则报错)。

conftest.py文件内容如下:

import pytest
​
@pytest.fixture(scope='class')
def class_fixture():
    print('我是一个类级前置')
    yield
    print('我是一个类级后置')

test_01.py文件内容如下:

import pytest
​
@pytest.mark.usefixtures('class_fixture')
class TestSome():def test_one(self):
        print('one')def test_two(self):
        print('two')

pytest运行test_01.py会自动运行执行引用的夹具

5.夹具的多层使用
import pytest
​
@pytest.fixture
def fixture1():
    print('>1111111')
    yield
    print('1111111<')@pytest.fixture
def fixture2():
    print('>222222')
    yield
    print('222222<')@pytest.fixture(scope='module')
def module_fixture():
    print('模块前置')
    yield
    print('模块后置')# 如果有多重夹具,先执行作用范围大的
# 当作用范围相同时,执行先修饰的(参数的传入顺序)
def test_func(fixture1,fixture2,module_fixture):
    print('test_func')

6.夹具的继承

除了可以在测试函数中使用夹具外,夹具功能还可以使用其他的夹具。这有助于夹具的模块化设计,并允许在许多项目中重复使用特定的夹具。

注意夹具的使用只能是使用范围更广的夹具,反过来不行。模块级别的夹具不能使用类级别的夹具。

import pytest
@pytest.fixture
def fixture1():
    print('》11111')
    yield 1
    print('11111《')# 夹具在继承的时候,被继承的夹具范围要大于等于继承夹具
@pytest.fixture
def fixture2(fixture1):   # 需要fixture1的结果
    fixture1 += 1
    print('》22222')
    yield fixture1
    print('22222《')def test_func(fixture2):
    print(fixture2)
    print('test_func')

在这里插入图片描述

在这里插入图片描述

5、参数化

1. 写法一

import pytest
​
@pytest.fixture(params=['avs','vsd','cd3'])
def haha(request):
    print('这是前置的方法')
    yield request.param   #return和yield都表示返回的意思,但是return的后面不能有代码,yield返回后后面可以接代码
    print('这是后置的方法')class TestInterface:def test_03_interface(self):
        print('test03')def test_05_interface(self,haha):    #调用了haha方法,会将haha中传入的每个参数执行一次,一共执行三次
        print('test-05')
        print(str(haha))

参数传递过程:在@pytest.fixture(params=[‘avs’,‘vsd’,‘cd3’])中进行定义,通过request传入haha,request.param获取单个参数值,参数值通过调用函数时haha传入,此时haha=单个函数值

params=[‘avs’,‘vsd’,‘cd3’]这里params是参数名,有s

request.param这里是属性名,是没有s的

注:return和yield都表示返回的意思,但是return的后面不能有代码,yield返回后后面可以接代码

2. 写法二

import pytest
​
test_data=[
    {
        'num':1,
        'expect_data':1
    },
    {
        'num':-1,
        'expect_data':1
    },
    {
        'num':0,
        'expect_data':0
    }
]# 将test_data解包为多个case
@pytest.mark.parametrize('case',test_data)
def test_abs(case):
    assert abs(case['num'])==case['expect_data']

import pytest
​
test_data2=[
    [1,1],
    [-1,1],
    [0,0]
]# 将test_data2解包为多个数据,然后再次解包并赋值
@pytest.mark.parametrize('num,expect',test_data2)
def test_abs2(num,expect):
    assert abs(num)==expect

6、夹具别名

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

import pytest
​
@pytest.fixture(name='aaa')
def haha():
    print('这是前置的方法')
    yield
    print('这是后置的方法')class TestInterface:def test_03_interface(self):
        print('test03')def test_05_interface(self,aaa):  #通过别名调用
        print('test-05')   

取了别名之后,函数原本的名称不可

四、生成报告

1、生成测试报告

pytest生成测试报告需要安装插件,请按插件说明来操作官方地址

2、生成allure报告

allure是一个专门生成测试报告的框架,支持多种语言和测试框架官方文档

3、下载、解压、配置path路径

地址
解压后运行bin目录下allure.bat文件

配置path路径:【计算机–属性–高级系统设置–环境变量–系统变量–path–编辑】(E:\test ruanjian\allure-commandline-2.14.0\allure-2.14.0\bin)

验证:打开dos窗口,输入命令allure --version

问题:dos可以验证但是pycharm验证失败,则重启pycharm

4、加入命令生产json格式的临时报告

在pytest命令中带上参数 --alluredir ,指定报告生成的路径

–alluredir ./temp

import pytest
if __name__ == '__main__':
    pytest.main(['-vs','--alluredir=./temp/my_allure_results'])   #主函数模式
    
pytest --alluredir ./temp/my_allure_results   #命令行模式
#也可在配置文件中进行修改

5、生成allure报告

查看报告需要通过命令行启动allure服务

allure serve ./tmp/my_allure_results

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

allure generate #命令,固定的
./temp #临时的json格式报告的路径
-o #输出output
./report #生成的allure报告的路径
–clean #清空./report路径原来的报告

6、上面的几个我没尝试觉得烦这边看这个

在这里插入图片描述

五、pytest.ini配置文件

pytest.ini这个文件是pytest单元测试框架的核心配置文件(配置文件中,因编码格式问题,需删除注释)

1、存放位置

一般放在项目的根目录

在这里插入图片描述

2、 编码格式

必须是ANSI,可以使用notpad++修改编码格式,或者新建txt文本,后另存文件为ANSI编码,修改文件名称
在这里插入图片描述

3、作用

改变pytest默认的行为/规则

4、规则明细

不管是主函数的模式运行,命令行模式运行,都会去读取这个文件

[pytest]
addopts=-vs                 #命令行的参数,可以输入多个,用空格分隔,主函数和命令行模式处直接执行
testpaths=./testcase        #测试用例的路径
python_files=test_*.py      #配置测试搜索模块名的规则
python_classes=Test         #配置测试搜索类名的规则
python_functions=test       #配置测试搜索方法名的规则(函数)
markers=                    #标记的模块
    smoke:冒烟用例
    uermanage:用户管理模块
    productmanage:商品管理模块

六、分组执行(冒烟、分模块执行,分接口和web执行)

1.在pytest.ini文件中配置标记的模块
在这里插入图片描述
2.在用例处插入标记
在这里插入图片描述
3.通过主函数模式或命令行模式调用mark实现分组执行

#主函数模式
import pytest
if __name__ == '__main__':
    pytest.main(['-vs','-m=smoke'])
    
import pytest
if __name__ == '__main__':
    pytest.main(['-vs','-m=smoke or product'])
    
#命令行模式
pytest -m 'smoke'
pytest -m 'smoke or product'

七、pytets跳过用例

1、无条件跳过

无条件跳过,定义用例

@pytest.mark.skip(reason='跳过原因,可不输入')

2、规定条件跳过

有条件跳过,定义用例

@pytest.mark.skipif(age>18,reason='跳过原因') #age>18为筛选条件,满足则跳过

3、运行

import pytest
if __name__ == '__main__':
    pytest.main()  #主函数
​
pytest #命令行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值