前言

pytest是python2自带的自动化测试框架,python3的版本的话pytest框架独立出来,需要pip进行安装

选取pytest框架作为自动化的框架,是经过多个框架对比之后的结果,它有一些相对的优势

相对比于unittest框架几个优势:

1.fixture前置功能

2.用例标记,用例重跑等功能。 

3.用例参数化 

4.兼容unittest,nose框架

其中的亮点功能也是fixture的功能,在后面单独介绍fixture功能

官方介绍pytest框架的优势:

1.非常容易上手,入门简单,文档丰富,文档中有很多实例可以参考

2.能够支持简单的单元测试和复杂的功能测试

3.支持参数化

4.执行过程只能怪可以将某些测试跳过或者对某些预期失败的case标记成失败

5.支持重复执行失败的case

6.支持运营由nose,unittest编写的测试case

7.可生成html报告

8.方便和持续集成工具jenkins集成

9.可支持执行部分用例

10.具有很多第三方插件,并且可以自定义扩展

能捉老鼠的就是好猫,能满足大部门需求的框架就是好框架,那怎么使用框架帮助做自动化测试,接收一波使用手册

1.一、下载安装

(1)python2自带,pytest --version直接查看,或者通过终端打开:import pytest,没报错,那就是存在的,但是python2
2020年之后就不维护了,所以最好及早的换成python3环境

(2)python3,pip install -U pytest

(3)查看下载的pip show pytest或者pytest --version

(4)pytest用例执行规则:

        ①测试文件以test_xx.py开头(或_test结尾)

        ②测试类以Test开头,并且不能带有init方法

        ③测试函数或方法以test_xx开头

tip:只能以此命名规则命名,自己命名一个文件为:test_create_trans,就无法识别,只能是test_xxx.py

二、测试用例设计与执行

*
主要亮点功能

*
@pytest.fixture

*
@pytest.mark.parametrzie

*
@pytest.mark

*
conftest.py文件

*
其他测试用例设计优质功能

*
pytest.xfail()

*
pytest.exit()

*
pytest.skip()

*
pytest.skipif()

2.1主要亮点功能介绍:

1.fixture功能

理解fixture功能:类似于unittest框架中的setup,teardown这种方法,无需显示调用,框架会自动执行,不过fixture不同之处

①可以显示调用,也可以设置自动调用

②显示调用,fixture直接作为其他测试用例参数传入

③直接通过scope参数范围确定执行的作用范围

④自定义前置操作的函数名,非固定的setup,teardown等

fixture语法:

@pytest.fixture(scope="session",autouse=True)

#scope分别有四个等级:session,module,class,function,function为默认的级别

#autouse表示该函数是否所有的测试用例都默认调用,True表示自动均调用login执行,False表示不自动调用

使用说明:

@pytest.fixture是pytest的装饰器,熟悉python语法的就知道装饰器,某个函数需要当做fixture功能使用的话,在函数前注册为fixture,具体参考应用实例部分代码

实现的功能:

可以将一些通用的,测试用例执行前都需要执行的方法提前执行,且会根据设置的session级别,确定在什么时候执行:

应用实例:以登录为实例:因为基本上所有的功能测试都需要用到登录,所以作为一个前置执行函数,如下:
#test_01.py # -*- coding:utf-8 -*- import pytest test_login =[{
        "username": "18712345678",         "passwd": "111111"     }]
@pytest.fixture() def login(request):     username = request.param['username']
    passwd = request.param['passwd']     return
"登录名:{0},密码:{1}".format(username, passwd) @pytest.mark.parametrize("login",
test_login, indirect=True)
#参数化login,因为login,fixture中仅包含过程,不是固定的登录数据,那么在test_01需要用到哪个用户登录时候,再给参数化传值登录使用
def test_01(login):     #login作为一个参数传递给test_01测试用例     print "测试用例1:%s"%login
if __name__ == "__main__":     pytest.main(['-s', 'test_01.py'])

#但是必须注意:如果想要只执行一遍,fixture功能只能放在conftest中,就像本人将这个方法单独放置在一个公共的common文件中然后导入调用,那么每一个测试用例使用fixture作为参数传入,然后每一个测试用例都调用了一次login,执行一遍login

具体执行结果见下图

2.用例参数化功能

语法

@pytest.mark.paramertrize("参数名", list, indriect),

使用说明

#参数名:第一个参数需要一个字符串,字符串内容可以是函数,可以是测试用例所需参数

#list:对应参数化的数据要传一个列表,如果是几组数据,中间通过元组的形式,或者字段的形式再嵌套

#indriect:默认为False,含义:确认第一个参数是否传入的值为函数,如果是函数,需要传该参数为True,否则可不传

实现的功能:

可以实现测试用例的参数化,以及参数的组合,具体参照应用实例

应用实例:
#第一种参数化 @pytest.mark.parametrize("param01, param02", [(1, 2),(2, 3)])
@pytest.mark.parametrize("login", test_login, indirect=True) def test_02(login,
param01, param02 ):     print "登录成功:%s" % login     print
"测试数据:%s,%s"%(param01, param02) 执行结果:
#第二种参数组合,将param1,param2,分别参数化,pytest框架默认将参数进行排列组合传递给测试用例
@pytest.mark.parametrize("param01", [1, 2, 3])
@pytest.mark.parametrize("param02", [4,5]) @pytest.mark.parametrize("login",
test_login, indirect=True) def test_03(login, param01, param02):     print
"登录成功:%s" % login     print "测试数据:%s,%s"%(param01, param02)
执行结果:

3.用例标记功能

语法:@pytest.mark.xxx

使用说明:@pytest.mark.xxx中
xxx为标记名,个人定义,比如某个接口用例为web端的,某个接口用例为APP端的,那么可以区分标记,如:@pytest.mark.web
;@pytest.mark.app

实现的功能:区分标记用例,接上,如果只需要测试web端的,在命令行通过-m参数就可以指定需要执行的用例:

即$pytest -m web test_01.py

那么pytest就只会执行web的测试用例,具体结果参照应用实例部分

应用实例

* @pytest.mark.web @pytest.mark.parametrize("login", test_login,
indirect=True) def test_04(login):     print "%s"%login     print
"标记测试用例为web端用例" @pytest.mark.app @pytest.mark.parametrize("login", test_login,
indirect=True) def test_05(login):     print "%s"%login     print
"标记测试用例为app端用例"
执行结果

4.conftest文件:

conftest文件是pytest 框架默认读取的一个配置文件,所以需要注意:

①conftest.py配置脚本名称是固定的,不能修改名称

②conftest.py与运行的测试用例必须要在同一个package下,并且要有__init__.py

③不需要import导入conftest.py,pytest用例会自动查找

④如果要实现session级别的fixture,必须放在此文件下,如果新的文件封装fixture,无法实现session级别的调用

2.2 其他优质功能介绍

剩下的几个功能的话,使用简单也好理解

1.用例标记失败:pytest.xfail(msg) 

意思即:在哪种条件不满足的情况下,你是预期它是失败的,就将测试用例标记为失败的,msg是一个字符串

2.用例退出:pytest.exit(msg)

含义:在测试用例过程执行中,有一些方法是必须要通过之后,才可以给其他的方法用,比如登录,登录都失败了,那就不需执行其他的,就直接标记退出就可以了

3.用例跳过:有三种:

@pytest.mark.skip(reason="");

pytest.skip(reason)

pytest.mark.skipif(condition)

 #第一种@pytest.mark.ski是装饰器,可直接作用于一个方法或者类,

#第二三种非装饰器,在用例方法中执行跳过,第三种是在满足某种条件时在跳过,加了判断条件

以上几个具体用法可参考后面附加的代码
conftest.py文件 #conftest.py文件中注册的fixture def md5(text):     """将MD5方法封装"""
    hl = hashlib.md5()     hl.update(text.encode("utf-8"))     return
hl.hexdigest() @pytest.fixture(scope='session') def login(request):     """
    登录接口     :param request:     :return: r['data']
#即json中data字典,字典中包含了用户登录成功后的的基本信息     """     print
"登录成功:{0}".format(test_login_valid)     data = {         "username":
request.param['username'],         "password": md5(request.param['passwd']),
        "device_id": device_id,         "app_ver": request.param['app_ver']
    }     try:         r = BasePerformer.post(url, routes['login'], data)      
  #这里个人封装了post方法         if request.param['app_ver'] not in right_ver:
            assert r['code'] == 1108, "版本过低,请升级后登录"
            pytest.exit(r['errmsg'])         assert r['code'] == 1000
    except AssertionError:         pytest.exit(r['errmsg'])     except
Exception, e:         traceback.print_exc(file=sys.stdout)
        pytest.exit("登录异常,退出用例" + str(e))     else:         return r['data']
@pytest.fixture(scope='session') def get_trans(login):     """     运单概要接口
    trans_general     :param login:     :return:     """""     try:         r =
BasePerformer.get(url, routes['trans_general'], params={"token":
login['token']})         assert r['code'] == 1000         if not r['data'].
has_key("trans_number"):             pytest.exit("司机无运单,退出测试")         return
r['data']     except AssertionError:         pytest.exit(r['errmsg'])
    except Exception, e:         pytest.xfail(str(e))
测试用例文件:test_truck.py
@pytest.mark.parametrize("login", test_login_valid, indirect=True)
#此测试文件下的测试用例都需要用到login接口,所以直接在类前,声明使用fixture功能,那么在这个测试类执行前,就会直接去调用login class
TestTruck(object):     """车辆相关接口"""     def truck_info(self, login):
        """获取车辆信息接口"""         r = BasePerformer.get(url, routes['get_truck'],
params={'token': login['token']})         try:             if not r['data']:
                assert r['code'] == 1701  # 1701未绑定车辆                 #
pytest.skip("未绑定车辆,去绑定车辆")                 return False             assert
r['code'] == 1000             print "车牌为:%s" % r['data']['plate']
            return r['data']['plate']         except Exception, e:
            pytest.xfail("获取车辆信息失败" + str(e))
    @pytest.mark.parametrize("plate", plate_operate['plate'])
    @pytest.mark.parametrize("bound_type", plate_operate['bound_type'])     def
test_bound_plate(self, login, plate, bound_type):         """测试绑定车辆接口"""
        data = {             "token": login['token'],             "type":
bound_type,             "plate": plate         }         get_truck_info =
self.truck_info(login)         if (not get_truck_info) and bound_type == "1":
            print "当前未绑定车辆,直接绑定%s" % plate_operate         elif get_truck_info
== drive_plate:             print "当前已绑定司机个人车辆"
            pytest.skip("车辆已绑定正确,跳过用例")         elif get_truck_info !=
drive_plate and bound_type == "1":             print
"当前绑定车辆非司机个人车辆{0},先进行解绑".format(get_truck_info)             data["type"],
data["plate"] = "2", get_truck_info         print data         r =
BasePerformer.post(url, routes['bind_truck'], data=data)         try:
            assert r['code'] == 1000             plate = r['data']['plate'] if
plate_operate['bound_type'] == "1" else r['data']             return plate
        except Exception, e:             pytest.exit("车辆未绑定成功,退出用例")
            pytest.xfail(str(e))
2.3测试用例执行

测试用例编写过程中呢,边写边执行,执行的方式呢可以有两种:

①命令行模式:

pytest [options] [file]

具体的参数包含哪些可以通过$pytest --help查看

常用的就是-s,-m,-q

②pycharm执行

需要以py.test方式执行,Pycharm具体设置步骤:File-Settings-Tools-Python Integrated Tools,具体见下图:

三、测试报告生成

第二步执行用例,完了不管是pycharm还是命令行也都会记录一个测试结果,但是不够直观,所以利用插件,更直观的去看测试报告

3.1.简易版测试报告:pytest-html

(1)pytest-html安装

pip install pytest-html

pip show pytest-html

#查看是否安装成功

(2)pytest-html生成测试报告

①切换到要执行文件的目录

$pytest --html=report.html

#默认会将报告存在与当前路径下

②执行指定用例

pytest test_exception.py --html=../reports/test_exception.html

#test_exception.py为需要执行的用例

#../reports/  专门创建了一个文件夹用于存储测试报告,此为目录地址

#test_exception.html为测试报名名称

(3)测试重跑

$ pip install pytest-rerunfailures

$ pip show pytest-rerunfailures

#失败用例重跑:

pytest --reruns 1 test_exception.py --html=../reports/test_exception.html

#添加--reruns参数表示重跑,1表示重跑次数

--reruns=RERUNS  #RERUNS为重跑次数,默认为0

--rerunns-delay=RERUN_DELAY  #RERUN_DELAY为失败后间隔多少秒重新执行,时间单位为:s

 报告页的样式就如下:

3.2.Pytest+Allure生成高大上测试报告

需要准备:

pycharm:因为allure生成的html报告无法打开,通过pycharm打开可以正常显示

pytest-allure-adaptor:具体作用:即为了生成xml的测试报告

allure2.7.0 具体作用:allure工具将xml生成html的形式报告

java1.8:allure的依赖环境

1.下载pytest-allure-adaptor

pip install pytest-allure-adaptor

pip show pytest-allure-adaptor

2.尝试通过pytest-allure-adaptor生成测试报告的xml文件

$pytest -s -q test_trans.py --alluredir report

#即将test_trans.py的测试结果存入report目录下,report即在当前目录下新建一个report目录,也可以重新指定

3.下载allure,

下载最新版本allure2,下载安装之后,将"E:\allure-2.7.0\bin"添加到环境变量中,为了后面使用命令,就和其他软件使用命令行方法一样,添加环境变量,一般添加完之后需要重新启动电脑

4.通过allure命令将xml文件生成html报告

allure generate allure生成的测试xml文件目录/ -o 测试报告目的存放目录/

如:allure generate --clean allure_xml/2019-02-21 -o allure_html/2019-02-21

#--clean表示重写报告

#执行完成进入生成报告目录,会看到一个index.html文件

5.通过pycharm打开测试报告

因为直接打开显示异常,所以通过下面的步骤,所以通过下面的方式查看

Allure报告展示

 

技术
©2020 ioDraw All rights reserved
【2020最牛小程序:你想要的各种资源都能搜的到?】C语言简易学生成绩管理系统运维工作梳理韭菜的愤怒:谷歌删除近10万条对Robinhood的负面评论Tampermonkey(油猴)的获取方法【技巧】简单几招解决Mac磁盘空间不足的问题惹什么猫都别惹熊猫!「功夫熊猫」20年对人类拿下4血为什么保持代码整洁如此重要?玩转指针重难点(1) 如何用SSL减少网站不必要的漏洞