python-pytest使用(1)

一、安装:

    1、基础包安装:pip install pytest

    2、引用:import pytest #pip安装后,会在python安装目录的\Lib\site-packages下安装pytest.py文件,这样在使用时直接import pytest就行了

 

二、案例引入,先看个示例:

"""文件名:test_001.py"""
def fun(a):
    return a+1
def test_001():
    assert fun(2)==3
def test_002():
    assert fun(2)==4

运行:在cmd命令框中输入:pytest test_001.py

执行结果:1个成功,1个失败

python 机器学习如何预测test文件并且输出到另一个文件中 python中的test_xml

    说明:测试文件后边的字母代表含义汇总:

        “.” 代表测试通过,

        F(Fail):失败

        E(error):错误

        s(skip):跳过

        X(xpass):预期失败但是成功x,

        xfail:预期失败执行也失败了.

三、理论部分

    1、文件、包、类、函数编写规则:

        文件或(包):必须以test_开头 或以_test结尾

        类:必须以Test开头,且不含init方法

        函数/方法:必须以test_开头

    2.断言方法:assert

        assert aa :判断aa为真

        assert not aa :判断aa不为真

        assert a in b :判断b包含a

        assert a == b :判断a等于b

        assert a != b :判断a不等于b

        另外:如果断言后有错误的,想给出友好提示可以用下面方式:

    assert 5 == add(4,4),"add()方法结果不等于5,而等于{0}".format(add(4,4))

    3.相关使用

        3.1 重复执行失败用例:pip install pytest-rerunfailures

            使用示例:pytest test.py --reruns 3

        3.2 测试报告: pip install pytest-html

            使用示例:pytest test.py --html=./testreport.html

            执行后生成如下报告:

python 机器学习如何预测test文件并且输出到另一个文件中 python中的test_html_02

 

        3.3 顺序随机测试:pip install pytest-randomly

        3.4 分布式并发测试用例集:

            pip install pytest-xdist 或  pip install pytest-parallel  

       备注:pytest-parallel支持python3.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个线程运行。

     见官方文档:https://pypi.org/project/pytest-parallel/

        3.5 出错立即返回:pip install pytest-instafail

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

            使用命令:pytest --junitxml=path

            使用示例:

pytest test.py --reruns 3 --html=./testreport.html --junitxml=xmlreport.xml

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

        3.7 参数化:

            A.fixture中无参数,使用示例:

            @pytest.fixture()

            代码示例:

import pytest
def fun():
    return "hello world"
@pytest.fixture()   #添加fixture后,执行inty方法就是执行fun()方法
def inty():
    return "connect to "+fun()
class TestCase():
    #inty参数名必须同fixture的inty方法名相同才能传递inty的值
    def test_open_baidu(self, inty):    
        print("============{}".format(inty))

执行后部分测试报告如下:

python 机器学习如何预测test文件并且输出到另一个文件中 python中的test_用例_03

        B.fixture中带有参数,使用示例:

        @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))

        执行后测试报告如下: 报告中用例都执行了2次,使用了params中的两个测试数据

python 机器学习如何预测test文件并且输出到另一个文件中 python中的test_html_04

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

            C.测试用例方法前直接加测试数据

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))

执行后测试报告如下:

python 机器学习如何预测test文件并且输出到另一个文件中 python中的test_html_05

D.测试用例方法前直接调用外部文件实现数据驱动

# -*- 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))

python 机器学习如何预测test文件并且输出到另一个文件中 python中的test_html_06

 

四、命令行运行

1.运行某个目录下全部用例

    pytest -q ..\pytestAllure #运行当前文件所在目录的下所有case

    即运行pytestAllure目录下所有test_*.py 或者*_test.py文件里的以Test开头的类(无__init__方法)下以test开头的方法

2.运行某py文件里的所有用例(即以Test开头的类下以test开头的方法)

    pytest test_demo1.py

3.运行包含关键词的类或方法

pytest -k Test_pytestClass1 ..\pytestAllure   
#执行pytestAllure目录下Test_pytestClass1 类下的所有test开头的case
pytest -k Test_pytestClass1 && case11 ..\pytestAllure   
 #执行pytestAllure目录下Test_pytestClass1 类下的所有case名包含case11的

4.用节点id来运行  用::来标识节点追踪方式

pytest test_demo1.py::Test_pytestClass1    
#执行test_demo1.py文件中的Test_pytestClass1类下所有test开头的方法

    执行后提示:

====1 failed, 1 passed, 1 warnings in 0.11 seconds ====

pytest test_demo1.py::Test_pytestClass1::test_case12  
#执行test_demo1.py文件中的Test_pytestClass1类下的test_case12方法

执行后提示:

========== 1 failed, 1 warnings in 0.10 seconds ==========

5.怎么从包下运行所有用例

    pytest --pyargs pkg.testing

    这将导入pkg.testing并使用其文件系统位置来查找和运行测试。

6.怎么执行带@pytest.mark.errorcase的类或方法

pytest test_demo1.py -m errorcase  #执行test_demo1.py文件中的标记为errorcase的test用例或类下全部test用例

代码:

@pytest.mark.errorcase
def test_case12(self):
assert 4==3,"两个数不相等"

执行后提示:

======1 failed, 1 deselected, 1 warnings in 0.10 seconds ======

7.怎么执行多个mark标记的类或方法

pytest test_demo1.py -m "case12 or case13"    
#执行标记为case12和case13 的
pytest test_demo1.py -m "not case13"  #不执行标记为case13的

代码:

def test_case11(self):
assert 3==3,"两个数相等"
@pytest.mark.case12
def test_case12(self):
assert 4==3,"两个数不相等"
@pytest.mark.case13
def test_case13(self):
assert 5==3,"两个数不相等"

执行后提示:

====== 2 failed, 1 deselected, 2 warnings in 0.12 seconds =====

8.怎么跳过指定类或方法

    pytest test_demo1.py

代码如下:

@pytest.mark.skip  #skip可以放在类前(跳过类),也可以放在方法前(跳过方法)
def test_case14(self):
assert 11==3,"两个数不相等"

执行后:

==== 0 failed, 0 passed, 1 skipped, 2 warnings in 0.11 seconds ====

9.怎么重复执行失败用例

pytest test_demo1.py --reruns 3 --reruns-delay 5
#重复执行失败用例,且每次执行器等待5秒后再继续
执行示例:
pytest ..\pytestAllure --reruns 3 --reruns-delay 4

    执行后:

==== 4 failed, 2 passed, 1 skipped, 4 warnings, 12 rerun in 48.41 seconds =====

10.怎么生成html测试报告?

    pytest ..\pytestAllure   --html="testreport.html"  #执行完pytestAllure下所有用例后,当前目录下生成testreport.html的测试报告

11.怎么生成jenkins集成后可用的junit测试报告文件

pytest test_demo1.py --junitxml=junitxml.xml
#执行后生成junit可用的xml报告文件

执行示例:

pytest ..\pytestAllure --reruns 3 --reruns-delay 4 --html="testreport.html" --junitxml="junitxmlreport.xml"

 

执行后:

--generated xml file: D:\workspace\pytestAllure\junitxmlreport.xml ---

--generated html file: file://D:\workspace\pytestAllure\testreport.html --

==4 failed, 2 passed, 1 skipped, 4 warnings, 12 rerun in 48.41 seconds ==

12.怎么使用python命令运行pytest

    执行:python -m pytest testdemo.py

    备注:使用python执行的,可以顺便把当前目录加入到sys.path中,即环境变量

13.pytest的退出码汇总

    根据官方说法,提供了6种,分别如下:

    Exit code 0: 所有用例执行成功后则返回0

    Exit code 1: 所有用例执行后,有部分失败则返回1

    Exit code 2: 测试执行时被用户中断

    Exit code 3: 执行测试时发生内部错误

    Exit code 4: pytest 命令行使用错误

    Exit code 5: 没有收集到测试结果

    备注:如果是要自定义退出码,则需要配合插件:pytest-custom_exit_code

14.运行用例遇到失败就停止

    pytest -X testModu.py       #遇到用例失败就停止,后面的不执行

    pytest --maxfail=2 testModu.py #遇到第2个用例失败就停止,后面的不执行

###########一个比较全面的执行命令案例:#################

pytest -v test_demo1.py -k Test_pytestClass1 -m "case12 or case13" --reruns 3 --reruns-delay 3 --html=./report.html

以最详细的信息执行test_demo1.py文件中类名Test_pytestClass1 且用例名标记为case12或case13,如果有失败则重复运行3次且每次重复运行前等待3秒再继续,最后生成report.html报告

五、测试用例前置后置处理

# -*- coding:utf-8 -*-
'''
Created on 2019年8月6日
@author: George
前置、后置处理所有方法归纳如下:模块预处理:setup_module        teardown_module
类预处理:setup_class          teardown_class
函数预处理:setup_function      teardown_function
方法预处理:setup_method        teardown_method
用例预处理:setup              teardown
备注:pytest包会识别这些方法名
文件名:test_demo7.py
'''
import pytest
def setup_module():
    print("\n 这里是setup_module")
def teardown_module():
    print("这里是teardown_module")  
def setup_function():   
    print("这里是setup_function")
def teardown_function():   
    print("这里是teardown_function")
def test_case1():  
    print("这里是test_case1")
def test_case2():  
    print("这里是test_case2")    
    
class Testclass():
    def setup_class(self):  #类似于unittest里的@classmethod
        print("这里是setup_class")
    def teardown_class(self):
        print("这里是teardown_class")
    def setup(self):
        print("这里是setup")
    def teardown(self):
        print("这里是teardown")
    def setup_method(self):    #这里同setup方法作用其实一样   
        print("这里是setup_method")
    def teardown_method(self):
        print("这里是teardown_method")
    def test_ClassCase1(self):
        print("这里是test_testClassCase1")
    def test_ClassCase2(self):
        print("这里是test_testClassCase1")
    
if __name__=="__main__":
    pytest.main(["-s", "test_demo7.py"])    
    #备注:-s:显示用例执行结果信息;-q :只显示结果,不显示过程

备注说明:

1.这几种方法全部使用优先级顺序如下:

setup_module->setup_function->setup_class->setup_method->setup->

teardown->teardown_method->teardown_class->teardown_function->teardown_module

2.其中setup_method/teardown_method 和setup/teardown 用在一起作用是一样的

3.setup_function/teardown_function是用在类以外,而setup_method/teardown_method 用在类之内

    好了,pytest基本使用已经介绍完了,开始写测试脚本用例吧,后面会再更新一些高级使用(如:数据共享和数据作用域)