pytest介绍

一、 pytest单元测试框架

  1. 什么是单元则试框架
    单元测试是指在软件开发当中,针对软件的最小单位(函数,方法)进行正确性的测试
  2. 单元则试框架
    java: junit和 testng
    python: unittest和pytest
  3. 单元则试框架主要做什么?
    1、测试发现:从多个文件里面去找到我们测试用例
    2、则试执行:按照一定的顺字和规则去执行。井生成结果
    3、测试判断:通过断言判断预明结果和实际结果的差异
    4、测式报告:統计题试进度,耗时,通过率,生成测试报告

二、pytest简介

  1. pytest是一个非常成熟的 python的单元框架,比 unittest更灵活,容易上手
  2. pytest可以和 selenium, requests, apium结合实现web自动化,接口自动化,app目动化。
  3. pytest可以实现测试用例的跳过以及 失败用例重试
  4. pytest可以和 allure:生成非常美观的测试报吉
  5. pytest可以和 Jenkinsi持集成
  6. pytest有很多非第强大的插件,井且这些插件能够实现很多的实用的操作
pytest
pytest-html              #生成htm格式的目动化测试报告
pytest-xdist			 #测试用例分布式执行。多CPU分发
pytest-ordering			 #用于改变测试用例的执行顺序
pytest-rerunfailures	 #用例失败后重跑
allure-pytest			 #用于生成美观的测试报告


放到 requirements.txt中,通过 pip install -r requirements.txt

allure下安装参考:安装方法
安装好后安装allure-pytest插件

三、使用 pytest,默认的测试用例的规则以及基础应用

  1. 模块名必须以test开头或者test吉尾
  2. 试类必须以Test开头,并且不能有init方法。
  3. 测试方法须以test开头

四、pytest测试用例的执行方式

  1. 主数榎式
    (1)运行所有: pytest.main()
    (2)指定模块: pytest.main("-vs’, test_login.py])
    (3)指定目录: pytest. main(’-vs’, ’ /interface_ testcase)
    (4)通过 nodeid指定用例运行: nodeid由模块名,分隔行,类名,方法名,数名组成
       pytest. main(’-vs’, / interface_testcase/test interface py. 04 func))
       pytest main(’-vs’ /interface_testcase/test interface::pytestintertace_03_zhiliao)

  2. 命令行榎式
    (1)运行所有: pytest
    (2)指定模块: pytest- vs test_login. py
    (3)指定目录: pytest- vs /interface_ testcase
    (4)指定目录: pytest- vs / interface_ testcase/test_interface. py::test_04_func

  3. 参数详解

-S:表示输出试信息,包括 print打印的信思
v:显示更细的信息
-vs:这两个参数数一起用
-n:支持多线程或分布式运行测试用例。
如: pytest -vs /testcase/test_login.py -n 2
reruns NUM:失败用例重跑

X:表示只要要一个用例服错,那么测试停止
-maxair=2    出现两个用例失败就停止
k:根据测试用例的部分字符串指定测试用例。
如: pytest -vs/ testcase- K "ao”
–html ./report/report.html :生成HTML的报告

  1. 通过取 pytest.ini 配置文件
    pytest.ini 这个文件它是 pytest单元测试框架的核心配置文件
    1、位置:一放在而国的目录
    2、必须是ANSI,可以便用 notpad++ 修改编码格式
    3、作用:改变 pytest认的行为
    4、运行的观则:不管主函数的模式运行、命令行模式运行、都会去读取这个配文併。
[pytest]
addopts = -vs --html ./report/report.html           #命令行的参数,用空格分隔
testpaths = ./testcase     #测试用例的路径
python_files= test_*.py   #模块名的规则
python_classes= Test*     #类名的规则
python_functions= test*    #方法名的规则

五、pytest执行测试用例的顺序

unittest :asclla的大小来绝对的执行的顺序
pytest:默认从上到下
改变默认的执行顺序:使用mark标记
@pytest.mark.run(order=3) 数值代表优先级,由1开始

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

smoke:冒烟用例,分布在各个模块里面
pytest -m “smoke”
pytest -m “smoke or usermanage or productmanage”

七、跳过测试用例

  1. 无条件跳过
@pytest.mark.skip(reason='测试')   #reason 写跳过的原因
  1. 有条件跳过
@pytest.mark.skipif(age>=18,reason='已成年')

八、pytest框架实现一些前后置(夹具,固件)的处理,常用三种方式

  1. setup/teardown,setup_class/teardown_class
import pytest


class  Test_login:

    #在每个用例之前执行一次
    def setup(self):
        print('在执行用例之前的初始化代码:打开浏览器')

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

    def teardown(self):
        print('在执行测试用例后的执行:比如关闭浏览器')

    def teardown_class(self):
        print('在每个类执行后执行:比如销毁日志对象,关闭数据库连接')

    @pytest.mark.run(order=3)
    @pytest.mark.smoke
    def test_1(self):
        print('测试')

    @pytest.mark.run(order=1)
    @pytest.mark.usermanage
    def test_2(self):
        print('测试')


    @pytest.mark.skip
    def test_3(self):
        print('测试')

    def test_4(self):
        print('测试')


if  __name__  == "__main__":
    pytest.main(['-vs','./','--reruns=2'])    #--reruns=2  表示失败的地方重跑两次
  1. 二、使用@pytest.fixture()装饰器来实现部分用例的前后置
    @pytest.fixture(scope="", params="", autouse="",ids="",name="")
    (1) scope表示的是被@pytest.fixture标记的方法的作用域 ,function(默认), class, module,package/session
    == function:每个方法执行一次(autouse=True的时候)
    class:每个类执行一次
    module:每个py文件执行一次
    package/session:
    ==
    (2) params:参数化(支持列表,元组,字典列表,字典元组)
    (3) autouse=True:自动执行,默认 False
    (4)ids:当使用 params参数化时,给每一个值设置一个变量名。意义不大。
    (5)name:始表示的是被@ pytest.fixture标记的方法取一个别名
#####scope的使用

import pytest



@pytest.fixture(scope='function')
def my_fixture():
    print('这是前置的方法')
    yield
    print('这是后置的方法')


class Test_one:

    def test_01(self):
        print('01')

    def test_02(self,my_fixture):
        print('02')


if  __name__  == '__main__':
    pytest.main(['-vs','./test_01.py'])

================运行结果=======================
test_01.py::Test_one::test_01 01
PASSED
test_01.py::Test_one::test_02 这是前后置方法
02
PASSED

============================== 2 passed in 0.02s ==============================

####params的使用
import pytest



@pytest.fixture(scope='function',params=['test1','test2','test3'])
def my_fixture(request):  #使用request 固定写法
    print('这是前置的方法')
    yield
    print('这是后置的方法')
    return request.param   #param此时没有s

class Test_one:

    def test_01(self):
        print('01')

    def test_02(self,my_fixture):
        print('02')
        print('------------'+str(my_fixture))


if  __name__  == '__main__':
    pytest.main(['-vs','./test_01.py'])

==========================打印结果=======================
test_01.py::Test_one::test_01 01
PASSED
test_01.py::Test_one::test_02[test1] 这是前置的方法
02
------------None
PASSED这是后置的方法

test_01.py::Test_one::test_02[test2] 这是前置的方法
02
------------None
PASSED这是后置的方法

test_01.py::Test_one::test_02[test3] 这是前置的方法
02
------------None
PASSED这是后置的方法

============================== 4 passed in 0.03s ==============================

  1. 通过 conftest.py和@pytest.fixture() 结合使用实现全局的前置应用(比如:项目的全局登录,模块的全局处理)
    1、 conftest. py文件是单独存放的一个夹具配置文件,名称是不能更改
    2、用处可以在不同的py文件中使用同一个fixture图数
    3、原则上 conftest.pyi需要和运行的用例放到统一层。并且不需要做任何的import导入的操作

总结
setup/teardown, setup_ class/teardown_class它是作用于所有用例或者所有的类
@ pytest.fixtrue() 它的作用是既可以部分也可以全部前后
contest.py和@pytest.fixtrue()结合使用,作用于全局的前后置
在这里插入图片描述

#######test_one.py里面的代码
class Test_one:

    def test_01(self,cc):
        print('01')

    def test_02(self):
        print('02')


#############test_two.py里面代码

class Test_two:

    def test_01(self):
        print('01')

    def test_02(self,cc):
        print('02')
        print("---------------------"+str(cc))

#########conftest.py里面的代码
import pytest


@pytest.fixture(scope='function',params=['cc'],name='cc')
def my_fixture(request):  #使用request 固定写法
    print('这是前置的方法')
    yield
    print('这是后置的方法')
    return request.param   #param此时没有s

#############run里面的代码
import pytest


if __name__ == '__main__':
    pytest.main(['-vs','./test_case/manage'])

#######################运行结果#################################
test_case/manage/test_01.py::Test_one::test_01[cc] 这是前置的方法
01
PASSED这是后置的方法

test_case/manage/test_01.py::Test_one::test_02 02
PASSED
test_case/manage/test_02.py::Test_two::test_01 01
PASSED
test_case/manage/test_02.py::Test_two::test_02[cc] 这是前置的方法
02
---------------------None
PASSED这是后置的方法


============================== 4 passed in 0.03s ==============================
九、断言

assert

assert 1==2

十、pytest结果allure-pytest插件生成allure测试报告

  1. 下载,解压,配path路径
    https://github.com/allure-framework/allure2/releases
    在这里插入图片描述
    path路径配置
    验证: allure-- version
    pycharm需要重启才能获取到

  2. 加入命令生成json格式的临时报告
    –alluredir ./temp

  3. 生成 allure报告
    os.system( ‘allure generate ./temp -o report -clean’)
    allure generate 命令,固定的
    ./temp 临时的json格式报告的路径
    -0 输出 output
    /report 生成的 allure报告的路径
    -clarn 清空 report路径原来的报吉

###############pytest.ini的代码
[pytest]
addopts = -vs --alluredir ./temp
testpaths = ./
python_files = test_*.py
python_classes = Test*
python_functions = test*
markers =
    smoke:冒烟测试
    usermanage:用户管理模块


###########run文件代码
import pytest
import os

if __name__ == '__main__':
    pytest.main(['-vs','./test_case/manage'])
    os.system('allure generate ./temp -o report --clean')

生成的报告文件
在这里插入图片描述

十一、补充—pytest中的装饰器@ pytest.mark. parametrize()的基础用法。

一、 数据驱动:其实就是把我们测试用例的数据放到 excel,yaml,csv, mysql.然后通过去改变数据达到改变测试用例的执行结果

@pytest.mark.parametrize(args_name, args_value)
args_name:参数的名称
args_value:数的值 (list,tuple,字典列表,字典元组)

pytest默t认的测试用例的规则( pytest ini)
1、模块名必须以test或音是_test开头
2、类名必须以Test开头
3、方法名必须以test开头

import pytest


class Test_api:
    
    #最基础的用法
    @pytest.mark.parametrize('cc',['test1','test2','test3'])
    def test_01(self,cc):
        print(cc)

    #解包的方法
    @pytest.mark.parametrize('name,age',[['test1','18'],['test2','20'],['test3','21']])
    def test_02(self,name,age):
        print(name,age)
        
if __name__ == '__main__':
    pytest.main(['-vs','./test.py'])

#####运行结果#################
test.py::Test_api::test_01[test1] test1
PASSED
test.py::Test_api::test_01[test2] test2
PASSED
test.py::Test_api::test_01[test3] test3
PASSED


test.py::Test_api::test_02[test1-18] test1 18
PASSED
test.py::Test_api::test_02[test2-20] test2 20
PASSED
test.py::Test_api::test_02[test3-21] test3 21
PASSED

============================== 6 passed in 0.04s ==============================

二、 yaml文件语法规则详解
  1. yaml简介
    yaml它是一个数据文件,保存的一个数据格式,支持注释,换行,裸字符串(最小单位的数据)
  2. yaml用法
    (1)用于全局配置文件:环境,数据库信息,账号信息,日志格式,报告名称
    (2)用于接口目动化里面的多一些复杂的多接口串联
    (3)用于编写接口测试用例
  3. YAML语法规则
    (1)区分大小写
    (2)和 pythonー样也是通过缩进的方式来表示层级关系(不同的是不能使用ab縮进,只能用空格)
    (3)和缩进多少层无关,只和左边是否对齐有关系
    (4)#表示注释
  4. YAML数组组成车例
    1.map对象健(空格)值
    2.数组(列表):用一组横线开头

实例:

##################################yaml内容:
-
  api_name: 获取网易新闻
  api_request:
    url: https://api.apiopen.top/getWangYiNews
    method: post
    headers:
     Content-type: application/json
    params:
     page: 1
     count: 5
  api_valldate:
    - eq: {code: 200,message: '成功'}


##################################读取yaml文件代码:
import yaml



def read_yaml(yaml_file):
    """
    读取yaml文件
    :return:
    """
    with open(yaml_file,encoding='utf-8') as f:
        data = yaml.load(f, Loader=yaml.FullLoader)
    return data


##############################################用例:
import pytest
from Common.read_yaml import read_yaml
import requests


class Test_api:

    @pytest.mark.parametrize('args',read_yaml('./case_01.yaml'))
    def test_wy(self,args):
        url = args['api_request']['url']
        method = args['api_request']['method']
        headers = args['api_request']['headers']
        params = args['api_request']['params']
        assertion = args['api_valldate']

        if method == 'get':
            res = requests.get(url)
        else:
            res = requests.post(url=url,json=params,headers=headers)
            for i in assertion:
                if i['eq']['code'] == res.json()['code'] and i['eq']['message'] == res.json()['message']:
                    print('测试成功')


if __name__ == '__main__':
    pytest.main(['-vs','./test.py'])

十二、补充----allure自定义报告

使用方法参数值参数说明
@alllure.epic()epic描述项目描述,往下是feature
@allure.feature()模块名称功能点的描述,往下是story
@allure.story()用户故事用户故事,往下是title
@allure.title()用例的标题重命名HTML报告的名称
@allure.testcase()测试用例的链接地址对应测试用例系统里面的case
@allure.issue()缺陷对应缺陷管理系统里面的链接
@allure.description()用例描述测试用例的描述
@allure.step()操作步骤测试用例的步骤
@allure.severity()用例等级blocker、critical、normal、minor、trivial
@allure.link()链接定义一个链接,在测试报告展示
@allure.attachment()附件报告添加附件

在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值