栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

pytest基础(1)

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

pytest基础(1)

python有很多不错的测试框架,比如RobotFramework,Unitest,这里要介绍一下pytest。可以参考,pytest文档
因为文档介绍比较多,这里使用简单的几篇帖子引导快速入门并灵活使用。

1 安装和执行

通过安装和一个简单的实例先入为主,体验一下如何使用。

pip3 install pytest

安装之后在在python37libsite-packages目录下安装对应的pytest包,使用的时候直接引入import pytest即可。

2 用例
"""文件名:test_001.py"""
def fun(inputNum)->int:
    return inputNum+1
def test_001():
    assert fun(2)==3
def test_002():
    assert fun(2)==4

在命令行执行:pytest test_001.py

python脚本以test或者test命名后,执行对应的pytest 文件名.py即可执行
说明:测试文件后边的字母代表含义汇总:

  • .:绿色表示执行通过
  • F :Fali失败
  • E:Error错误
  • s:Skip跳过
  • X:Xpass预期失败但是成功
  • xfail:有切失败执行失败
3 pytest入门知识 3.1 命名规范

pytest中,命名要求:

  • 文件/包需要以test_开头或者_test结尾
  • 类名必须以Test开头,且不含__init__方法
  • 方法/或者函数,必须以test_开头
3.2识别断言

pytest中断言判断使用assert,主要有以下几种断言

assert flag # 断言flag为True
assert not flag #断言flag为False
assert subset in set #断言subset存在于set中
assert a == b #断言a等于b
assert a != b #断言a和b不相等
3.3 pytest使用命令 1.重试

有时候可能因为环境等问题导致用例执行失败,此时考虑到重复执行,此时可以使用命令

# 安装rerun包
pip install pytest-rerunfailures

# 失败后重试3次
pytest test.py --reruns 3
2.测试报告

既然是介绍基本的知识,这里对于测试报告先使用html,如果深入了解后,可以使用allure展示测试报告,这里先介绍下html

pip install pytest-html
pytest test_001.py --html=./testreport.html


3.指定执行顺序

python的执行是从上到下依次执行,有时候需要做一些混沌测试,这个时候最好是可以顺序随机执行测试用例。

pip install pytest-randomly

具体使用方法可参考pytest-randomly

4.并发执行

python因为GIL的原因导致无法实现正在的多线程并发,因此可以根据其中的某些特性实现“并发请求”,从而减缓了大量请求的的sleep时间。主要有多线程(线程池),多进程,异步IO等。pytest中也有两种方式实现并发请求。

pip install pytest-xdist 
pip install pytest-parallel  # python version > 3.6

如果需要做多进程的并发,只能使用linux系统或者是mac。如果是多线程可以在windows上

–workers (optional)  * :多进程运行需要加此参数,  *是进程数。默认为1。
–tests-per-worker (optional)  * :多线程运行, *是每个worker运行的最大并发线程数。默认为1
pytest test.py --workers 3:3个进程运行
pytest test.py --tests-per-worker 4:4个线程运行
pytest test.py --workers 2 --tests-per-worker 4:2个进程并行,且每个进程最多4个线程运行,即总共最多8个线程运行。
5.出错后操作

常稳测试用例或者批量跑测试用例的时候,一般不希望其中一个用例执行失败后就结束整个自动化的运行过程。但是有时候确实有些特殊情况,需要在一遇到失败就就理解终止运行。

pip install pytest-instafail
6.集成报告

集成jenkins的junit报告: 不用安装pytest已经集成了

使用命令:pytest --junitxml=path

此时则执行完用例后,在本地目录生成testreport.html的测试报告,和xmlreport.xml的junit格式报告在jenkins中可调用展示。

7. 数据准备

数据准备比如执行case前需要给某个case准备好传递的参数数据。介绍参数之前,先说说测试的基本过程,一般可以分为4个步骤

  1. Arrange 安排或者说布局,执行测试所需要的设置和初始化
  2. Act 采取测试所需的行动
  3. Assert 验证测试结果
  4. Cleanup 环境恢复
    那pytest中的fixture几乎可以干了上面的124的工作。可参考fixture
fixture 无参
import pytest
def fun():
    return "hello world"

@pytest.fixture()
def inty():
    return "connect to "+fun()

class TestCase():
    #inty参数名必须同fixture的inty方法名相同才能传递inty的值
    def test_open_baidu(self, inty):
        print("============{}".format(inty))

**注意:**pytest.fixture()装饰器定义的对象名inty必须和方法调用的参数名inty一致

fixture有参

最常用的场景是,测试登录,比如给一个账户和ID,或者账户和密码,需要遍历各种类型测试其正确性

@pytest.fixture(params=[
{key11:value1,key12:value2} ,
{key21:value21,key22:value22}
]
)

import pytest
@pytest.fixture(params=[{'userID':'00001','username':'jack'},
                        {'userID':'00002','username':'mike'}])    
def getdata(request): #这里的request是固定参数名
    #分别打印params的字典项:{'userID': '00001', 'username': 'jack'} 
    #和{'userID':'00002','username':'mike'}
    print("request.param======",request.param)   
    return request.param    #这里的request.param也是固定的
class TestCase():
    def test_case1(self, getdata):    
        print("第1个用例输出:{}".format(getdata))
    def test_case2(self, getdata):
        print("第2个用例输出:{}".format(getdata))

**注意:**pytest.fixture(参数)传递参数时,在get属性中时,只能设置get方法的参数为request

这里可以看到每个用例执行了两次,第一次是执行第一个参数,第二次是验证第二个参数。
根据这样的例子,如果在测试中需要处理很多重复测试数据时,则这些数据就可以传入params里(可以另外写个方法读取txt/excel等文件测试数据值,以多字典列表形式返回所有测试数据),类似于unittest的DDT数据驱动方法。然后就会逐一去带入testcase里执行了

测试用例中某个方法前加指定的参数

测试过程中,建一个一个.py文件验证一个场景,这样是最为方便的(比如方便维护,方便其他teamer审阅功能等),但是有时候需要在某些方法前给其加上独有的参数

import pytest
class TestCase():
    @pytest.mark.parametrize("getdataA",
                        [{'userID':'00001','username':'jack'},
                        {'userID':'00002','username':'mike'}])
    def test_case1(self, getdataA):    
        print("第1个用例输出:{}".format(getdataA))
    @pytest.mark.parametrize("getdataB",
                        [{'userID':'00003','username':'tina'},
                        {'userID':'00004','username':'book'}])
    def test_case2(self, getdataB):
        print("第2个用例输出:{}".format(getdataB))

输出测试报告:

那结合上面fixture中有参数的场景和本节中给某个函数指定参数的场景

import pytest
@pytest.fixture(params=[{'userID':'00001','username':'jack'},
                        {'userID':'00002','username':'mike'}])
def getdata(request): #这里的request是固定参数名
    #分别打印params的字典项:{'userID': '00001', 'username': 'jack'}
    #和{'userID':'00002','username':'mike'}
    print("request.param======",request.param)
    return request.param    #这里的request.param也是固定的
class TestCase():
    def test_case1(self, getdata):
        print("第1个用例输出:{}".format(getdata))

    @pytest.mark.parametrize("getdataB",
                        [{'userID':'studenta','username':'tina'},
                        {'userID':'studentb','username':'book'}])
    def test_case2(self, getdataB):
        print("第2个用例输出:{}".format(getdataB))

输出测试报告:

既然在fixture有参章节中提到了使用外部数据作为入参进行传递,那么这里就跟着介绍一下

测试用例中方法前直接调用外部文件实现数据驱动
# -*- coding:utf-8 -*-
import pytest,csv
def getCsvContents(csvFileUrl):
    '''把csv格式文件转换为字典列表方法'''
    with open(csvFileUrl,'r') as csv_f:
        reader = csv.reader(csv_f)
        fieldnames = next(reader)
        csv_reader = csv.DictReader(csv_f,fieldnames=fieldnames)
        kwList=[]
        for row in csv_reader:
            d = {}
            for k, v in row.items():
                d[k] = v
            kwList.append(d)
    return kwList
class TestCase():
    @pytest.mark.parametrize("getdataA",getCsvContents('test.txt'))
    def test_case1(self, getdataA):    
        print("第1个用例输出:{}".format(getdataA))
    @pytest.mark.parametrize("getdataB",getCsvContents('test.txt'))
    def test_case2(self, getdataB):
        print("第2个用例输出:{}".format(getdataB))
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/920517.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号