接口自动化(二) 前后置(三种方法)、断言、allure报告

一、固件

setup/teardown,setup_class/teardown_class

为什么需要这些功能?比如:web自动化执行用例之前,需要打开浏览器,用例执行之后需要关闭浏览器

文件内容:

#创建一个python项目,目录结构:

test_firmware.py

import pytest

class Test_FirmWare():

    #setup_class/teardown_class在所有的测试用例之前、之后只执行一次
    def setup_class(self):
        print('\n-----在每个类执行前的初始化工作,如:创建日志对象、创建数据库的连接、创建接口的请求对象-----')

    #setup/teardown在每个测试用例之前、之后都要执行一次
    def setup(self):
        print('\n-----在执行测试用例之前初始化的工作,如:打开浏览器,加载网页-----')

    def test01(self):
        print('测试01')

    def test02(self):
        print('测试02')

    def teardown(self):
        print('\n-----在执行测试用例之后的扫尾工作,如:关闭浏览器-----')

    def teardown_class(self):
        print('\n-----在每个类执行后的扫尾工作,如:销毁日志对象、销毁数据库的连接、销毁接口的请求对象-----')

注意:和unittest不一样,这里全是小写

执行结果:

#可以看到setup_class/teardown_class只执行了1次,setup/teardown对每个测试用例都执行了一遍,共执行了2次

D:\JetBrains\PycharmProjects\Pytest_Fireware>pytest -vs

firmware/test_firmware.py::Test_FirmWare::test01
-----在每个类执行前的初始化工作,如:创建日志对象、创建数据库的连接、创建接口的请求对象-----

-----在执行测试用例之前初始化的工作,如:打开浏览器,加载网页-----
测试01
PASSED
-----在执行测试用例之后的扫尾工作,如:关闭浏览器-----

firmware/test_firmware.py::Test_FirmWare::test02
-----在执行测试用例之前初始化的工作,如:打开浏览器,加载网页-----
测试02
PASSED
-----在执行测试用例之后的扫尾工作,如:关闭浏览器-----

-----在每个类执行后的扫尾工作,如:销毁日志对象、销毁数据库的连接、销毁接口的请求对象-----

二、@pytest.fixture()

使用@pytest.fixture()装饰器来实现部分测试用例的前后置

setup/teardown,setup_class/teardown_class局限性较大,@pytest.fixture()则可以对全部测试用例设置前后置也可以对部分测试用例设置前后置

@pytest.fixture()语法:

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

(1)scope:表示的是pytest.fixture的作用域:函数(function(默认)),类(class),模块(module),包(package/session)

(2)autouse:Ture自动执行,False不自动执行,默认False

#演示:

#全局使用前后置:

代码1:对所有类执行前后置

test_fireware.py

import pytest

@pytest.fixture(scope='class',autouse=True)  #class表示作用域的是类,True表示对所有类都执行下面前后置方法
def my_fixture():  #my_fixture这个函数名可以自定义名称
    print('\n-----这是前置的方法-----')
    yield #yield作用是状态保持:函数暂停/恢复时自动保存所有状态 #return和yield都表示返回值。但return后面无法再跟代码,yield后面还可以跟代码,比如下面的print语句
    print('\n-----这是后置的方法-----')

class Test_FirmWare1():

    def test01(self):
        print('测试01')

    def test02(self):
        print('\n测试02')

class Test_FirmWare2():

    def test03(self):
        print('测试03')

    def test04(self):
        print('\n测试04')

执行结果:

D:\JetBrains\PycharmProjects\Pytest_Fireware>pytest -vs
================================================= test session starts =================================================

firmware/test_firmware.py::Test_FirmWare1::test01
-----这是前置的方法-----
测试01
PASSED
firmware/test_firmware.py::Test_FirmWare1::test02
测试02
PASSED
-----这是后置的方法-----

firmware/test_firmware.py::Test_FirmWare2::test03
-----这是前置的方法-----
测试03
PASSED
firmware/test_firmware.py::Test_FirmWare2::test04
测试04
PASSED
-----这是后置的方法-----


================================================== 4 passed in 0.01s ==================================================

代码2:对所有测试用例执行前后置

test_fireware.py

import pytest

@pytest.fixture(scope='function',autouse=True)  #将作用域修改为函数,并且对每个函数自动执行下面前后置方法
def my_fixture():
    print('\n-----这是前置的方法-----')
    yield
    print('\n-----这是后置的方法-----')

class Test_FirmWare1():

    def test01(self):
        print('测试01')

    def test02(self):
        print('测试02')

class Test_FirmWare2():

    def test03(self):
        print('测试03')

    def test04(self):
        print('测试04')

执行结果:

D:\JetBrains\PycharmProjects\Pytest_Fireware>pytest -vs
================================================= test session starts =================================================

firmware/test_firmware.py::Test_FirmWare1::test01
-----这是前置的方法-----
测试01
PASSED
-----这是后置的方法-----

firmware/test_firmware.py::Test_FirmWare1::test02
-----这是前置的方法-----
测试02
PASSED
-----这是后置的方法-----

firmware/test_firmware.py::Test_FirmWare2::test03
-----这是前置的方法-----
测试03
PASSED
-----这是后置的方法-----

firmware/test_firmware.py::Test_FirmWare2::test04
-----这是前置的方法-----
测试04
PASSED
-----这是后置的方法-----


================================================== 4 passed in 0.01s ==================================================

代码3:对所有模块执行前后置

test_fireware.py

import pytest

@pytest.fixture(scope='module',autouse=True) #改为module(模块),文件test_fireware.py就是一个模块
def my_fixture():
    print('\n-----这是前置的方法-----')
    yield
    print('\n-----这是后置的方法-----')

class Test_FirmWare1():

    def test01(self):
        print('测试01')

    def test02(self):
        print('测试02')

class Test_FirmWare2():

    def test03(self):
        print('测试03')

    def test04(self):
        print('测试04')

执行结果:

D:\JetBrains\PycharmProjects\Pytest_Fireware>pytest -vs
================================================= test session starts =================================================

firmware/test_firmware.py::Test_FirmWare1::test01
-----这是前置的方法-----
测试01
PASSED
firmware/test_firmware.py::Test_FirmWare1::test02 测试02
PASSED
firmware/test_firmware.py::Test_FirmWare2::test03 测试03
PASSED
firmware/test_firmware.py::Test_FirmWare2::test04 测试04
PASSED
-----这是后置的方法-----


================================================== 4 passed in 0.01s ==================================================

#部分使用前后置:

代码1:

test_fireware.py

import pytest

@pytest.fixture(scope='function')  #作用域为函数,关闭全局参数autouse
def my_fixture():
    print('\n-----这是前置的方法-----')
    yield
    print('\n-----这是后置的方法-----')

class Test_FirmWare1():

    def test01(self):
        print('测试01')

    def test02(self):
        print('测试02')

class Test_FirmWare2():

    def test03(self,my_fixture):  #仅给test03测试用例执行前后置
        print('测试03')

    def test04(self):
        print('测试04')

执行结果:

D:\JetBrains\PycharmProjects\Pytest_Fireware>pytest -vs
================================================= test session starts =================================================

firmware/test_firmware.py::Test_FirmWare1::test01 测试01
PASSED
firmware/test_firmware.py::Test_FirmWare1::test02 测试02
PASSED
firmware/test_firmware.py::Test_FirmWare2::test03
-----这是前置的方法-----
测试03
PASSED
-----这是后置的方法-----

firmware/test_firmware.py::Test_FirmWare2::test04 测试04
PASSED

================================================== 4 passed in 0.01s ==================================================

(3)params:参数化,支持字典[],元组(),字典列表[{},{},{}],字典元组({},{},{})

代码1: 

#先输出返回值试试

import pytest

@pytest.fixture(scope='function',params=['Tom','Jack','Andy'])  #注意这里的paeams是带s的
def my_fixture(request):  #需要传入一个request
    return request.param  #注意这里的param不带s

class Test_FirmWare1():

    def test01(self):
        print('测试01')

    def test02(self,my_fixture):  #调用my_fixture
        print('测试02')
        print('--------------'+my_fixture)  #输出my_fixture返回值

执行结果:

#可以看到test02用例被执行了三次,并且参数为params定义的三个参数

D:\JetBrains\PycharmProjects\Pytest_Fireware>pytest -vs
================================================= test session starts =================================================

firmware/test_firmware.py::Test_FirmWare1::test01 测试01
PASSED
firmware/test_firmware.py::Test_FirmWare1::test02[Tom] 测试02
--------------Tom
PASSED
firmware/test_firmware.py::Test_FirmWare1::test02[Jack] 测试02
--------------Jack
PASSED
firmware/test_firmware.py::Test_FirmWare1::test02[Andy] 测试02
--------------Andy
PASSED

================================================== 4 passed in 0.02s ==================================================

代码2:

#将前后置也加进来

import pytest

@pytest.fixture(scope='function',params=['Tom','Jack','Andy'])
def my_fixture(request):
    print('\n前置')
    yield request.param  #return和yield都表示返回值,因此这里只能有一个。但return后面无法再跟代码,yield后面还可以跟代码,比如下面的print语句
    print('\n后置')

class Test_FirmWare1():

    def test01(self):
        print('\n测试01')

    def test02(self,my_fixture):
        print('测试02')
        print('--------------'+my_fixture)

执行结果:

D:\JetBrains\PycharmProjects\Pytest_Fireware>pytest -vs
================================================= test session starts =================================================

firmware/test_firmware.py::Test_FirmWare1::test01
测试01
PASSED
firmware/test_firmware.py::Test_FirmWare1::test02[Tom]
前置
测试02
--------------Tom
PASSED
后置

firmware/test_firmware.py::Test_FirmWare1::test02[Jack]
前置
测试02
--------------Jack
PASSED
后置

firmware/test_firmware.py::Test_FirmWare1::test02[Andy]
前置
测试02
--------------Andy
PASSED
后置


================================================== 4 passed in 0.01s ==================================================

(4)ids :当使用params参数化时,给每一个值设置一个变量名

代码:

import pytest

@pytest.fixture(scope='function',params=['Tom','Jack','Andy'],ids=['a','b','c'])  #新增三个ids
def my_fixture(request):
    print('\n前置')
    yield request.param
    print('\n后置')

class Test_FirmWare1():

    def test01(self):
        print('\n测试01')

    def test02(self,my_fixture):
        print('测试02')
        print('--------------'+my_fixture)

运行结果:

D:\JetBrains\PycharmProjects\Pytest_Fireware>pytest -vs
================================================= test session starts =================================================

firmware/test_firmware.py::Test_FirmWare1::test01
测试01
PASSED
firmware/test_firmware.py::Test_FirmWare1::test02[a]  #这里变为了a
前置
测试02
--------------Tom
PASSED
后置

firmware/test_firmware.py::Test_FirmWare1::test02[b]  #这里变为了b
前置
测试02
--------------Jack
PASSED
后置

firmware/test_firmware.py::Test_FirmWare1::test02[c]  #这里变为了c
前置
测试02
--------------Andy
PASSED
后置


================================================== 4 passed in 0.01s ==================================================

(5)name:给被@pytest.fixture标记的方法取一个别名

代码:

import pytest

@pytest.fixture(scope='function',params=['Tom','Jack','Andy'],ids=['a','b','c'],name='Dance')  #给被@pytest.fixture标记的方法设置一个别名为Dance
def my_fixture(request):
    print('\n前置')
    yield request.param
    print('\n后置')

class Test_FirmWare1():

    def test01(self):
        print('\n测试01')

    def test02(self,Dance):  #调用的时候也得用别名,此时原来的名称就不生效了
        print('测试02')
        print('--------------'+Dance)  #调用的时候也得用别名,此时原来的名称就不生效了

执行结果:

D:\JetBrains\PycharmProjects\Pytest_Fireware>pytest -vs
================================================= test session starts =================================================

firmware/test_firmware.py::Test_FirmWare1::test01
测试01
PASSED
firmware/test_firmware.py::Test_FirmWare1::test02[a]
前置
测试02
--------------Tom
PASSED
后置

firmware/test_firmware.py::Test_FirmWare1::test02[b]
前置
测试02
--------------Jack
PASSED
后置

firmware/test_firmware.py::Test_FirmWare1::test02[c]
前置
测试02
--------------Andy
PASSED
后置


================================================== 4 passed in 0.02s ==================================================

三、夹具conftest.py

通过conftest.py和@pytest.fixture()结合使用实现全局的前后置应用(比如 : 项目的全局登录,模块的全局处理 )

1.conftest.py文件是单独存放的一个夹具配置文件,名称不能更改。

2.可以在不同的py文件中使用同一个fixture函数。

3.原则上conftest.py需要和运行的测试用例放到同一层目录,非同一层也可以。并且不需要做任何的imprt导入的操作。

#在实际使用中@pytest.fixture()不放到测试用例脚本中,而是放到固定名称的文件conftest.py中被调用

#演示:

目录结构:

文件内容:

product\conftest.py

import pytest

@pytest.fixture(scope='function')
def product_fixture():  #定义名为product_fixture的前后置方法
    print('\nproduct的前置')
    yield
    print('\nproduct的后置')

test_firmware1.py

import pytest

class Test_FirmWare1():

    def test_product(self,product_fixture):  #调用product_fixture前后置方法
        print('product测试')

 user\conftest.py

import pytest

@pytest.fixture(scope='function')
def user_fixture():  #定义名为user_fixture的前后置方法
    print('\nuser的前置')
    yield
    print('\nuser的后置')

test_firmware2.py

import pytest

class Test_FirmWare2():

    def test_user(self,all_fixture,user_fixture):  #先调用all_fixture前后置方法,再调用user_fixture前后置方法
        print('user测试')

#注意这里可以虽然调用根目录的全局前后置方法,但user目录下的不可以跨级调用product目录中的前后置方法

all.py  #执行文件

import pytest
if __name__ == '__main__':
    pytest.main()

conftest.py  #全局的conftest.py文件

import pytest

@pytest.fixture(scope='function')
def all_fixture():
    print('\n全局的前置')
    yield
    print('\n全局的后置')

pytest.ini  #配置文件

[pytest]
addopts = -vs
testpaths = ./
python_files = test_*.py
python_classes = Test*
python_functions = test

执行结果:

C:\Users\lasou\AppData\Local\Programs\Python\Python310\python.exe D:\JetBrains\PycharmProjects\Pytest_Fireware\all.py 
============================= test session starts =============================

product/test_firmware1.py::Test_FirmWare1::test_product 
product的前置
product测试
PASSED
product的后置

user/test_firmware2.py::Test_FirmWare2::test_user 
全局的前置

user的前置
user测试
PASSED
user的后置

全局的后置


============================== 2 passed in 0.04s ==============================

四、三种方式总结

setup/teardown,setup class/teardown class 它是作用于所有用例或者所有的类

@pytest.fixtrue() 它的作用是既可以部分也可以全部前后置

conftest.py和@pytest.fixtrue()结合使用,作用于全局的前后置

五、断言

文件内容:

test1_firmware1.py

import pytest

class Test_FirmWare1():

    def test_product(self,product_fixture):
        print('product测试')
        assert 1 == 2  #这里加一个断言 1==2明显错误,执行此测试用例就会报错

执行结果:

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

#allure-pytest相对与pytest-html插件生成的测试报告更美观

1.下载、解压、配置path路径

下载网址:https://github.com/allure-framework/allure2/releases

#本次使用2.13.7版本

#其他下载网址:https://repo1.maven.org/maven2/io/qameta/allure/allure-commandline/2.13.7/

解压到E盘:

配置path路径:

#注意配置完path后需要重新打开一次pycharm使之生效

2.增加命令生成json格式的临时报告

--alluredir ./temp

文件内容:

pytest.ini

[pytest]
addopts = -vs --alluredir ./temp  #表示生成json格式的临时报告
testpaths = ./
python_files = test_*.py
python_classes = Test*
python_functions = test

执行结果:

3.生成allure报告

 文件内容:

all.py

import pytest
import os

if __name__ == '__main__':
    pytest.main()
    os.system('allure generate ./temp -o ./report --clean')
#allure generate 固定命令
#./temp 临时的json格式报告路径
#-o 输出output
#./report 生成的allure报告的路径
#--clean 清空./report路径原来的报告

执行结果:

因此这个报告必须在pycharm上打开,或者使用“allure open allure-report 目录”命令打开才会渲染报告,否则报告中没有数据。

报告结构:
总览:汇总结果展示
类别:按照用例的类别,分类展示
测试套件:allure测试报告将每一个测试脚本,作为测试套件
图表:展示了此次测试结果的统计信息,比如测试用例执行结果状态、测试用例重要等级分布、测试用例执行时间分布等
功能:按照fixtures 和 stories 展示测试用例的执行结果
包:这就是按照package、module来分组测试用例了
测试用例详情页:测试套件页面点击任意一条测试用例,右侧展示详细信息。可以看到测试步骤,每个步骤的执行结果,还有测试用例的链接、图片、视频等内容。

posted on 2023-05-10 00:25  vorn  阅读(306)  评论(0)    收藏  举报

导航