pytest

  1. 导包 import unittest
  2. 测试类以Test开头
  3. 测试方法名称必须以test开头

pytest命令行运行
pytest test_case.py
显示详细信息
pytest -v test_case.py
pytest -v --return 2 --html=./report/demo_test_report.html test_case.py

Pytest的setup和teardown函数

1.setup和teardown主要分为:模块级,类级,功能级,函数级。
2.存在于测试类内部

import pytest


class TestABC(object):
    # 测试类级开始
    def setup_class(self):
        print("------->setup_class")

    # 测试类级结束
    def teardown_class(self):
        print("------->teardown_class")

    # 函数级开始
    def setup(self):
        print("------->setup_method")

    # 函数级结束
    def teardown(self):
        print("------->teardown_method")

    def test_a(self):
        print("------->test_a")
        assert 1

    def test_b(self):
        print("------->test_b")
        assert 0


if __name__ == '__main__':
    pytest.main()
Pytest配置文件

pytest的配置文件通常放在测试目录下,名称为pytest.ini,命令行运行时会使用该配置文件中的配置.
文件第一行 [pytest]

  • 配置pytest命令行运行参数
    详细信息输出 -v
    addopts = -v
    空格分隔,可添加多个命令行参数 -所有参数均为插件包的参数
    例如:addopts = -v --return 2 --html=./report/report.html
  • 配置测试搜索的路径
    当前目录下的scripts文件夹 -可自定义
    testpaths = ./scripts
  • 配置测试搜索的文件名
    以test_开头,以.py结尾的所有文件 -可自定义
    python_files = test_*.py
    -配置测试搜索的测试类名
    以Test_开头的类 -可自定义
    python_classes = Test_*
  • 配置测试搜索的测试函数名
    以test_开头的方法 -可自定义
    python_functions = test_*
Pytest常用插件

插件列表:https://plugincompat.herokuapp.com

  • html测试报告
    插件名称:pytest-html
    命令行格式:
    pytest --html=用户路径/report.html
    pytest --html=用户路径/report.xml
    例如:pytest -s --html=./report.html test_abc.py

  • Pytest控制函数执行顺序
    函数修饰符的方式标记被测试函数执行的顺序,默认情况下,pytest是根据测试方法名由小到大执行的,可以通过第三方插件包改变其运行顺序。
    插件名称:pytest-ordering
    @pytest.mark.run(order=x)修饰函数

    @pytest.mark.run(order=2)
    def test_a(self):
        print('\n-----------a')
        assert 1

    @pytest.mark.run(order=1)
    def test_b(self):
        print('\n------------b')
        assert 0

"""
test_abc.py 
------------b
F
-----------a
.
"""
  • Pytest失败重试
    通过命令行方式,控制失败函数的重试次数
    插件名称:pytest-rerunfailures
    命令行格式:pytest --reruns n
    n:为重试的次数
    例如:pytest -s --return 2 --html=./report.html test_abc.py
fixture

fixture修饰器来标记固定的工厂函数,在其他函数,模块,类或整个工程调用它时会被激活并优先执行,通常会被用于完成预置处理和重复操作。
比如测试用例的前置条件 的方法,可以用fixture修饰,在需要该前置条件的测试方法前调用。

方法:fixture(scope="function", params=None, autouse=False, ids=None, name=None)
常用参数:
scope:被标记方法的作用域
  function" (default):作用于每个测试方法,每个test都运行一次
  "class":作用于整个类,每个class的所有test只运行一次
  "module":作用于整个模块,每个module的所有test只运行一次
  "session:作用于整个session(慎用),每个session只运行一次
params:(list类型)提供参数数据,供调用标记方法的函数使用
autouse:是否自动运行,默认为False不运行,设置为True自动运行

import pytest


# --------------------------- 通过参数引用 函数级别 传入before的测试方法执行前会执行before------------------------------
class TestAAA(object):
    @pytest.fixture()
    def before(self):
        print("------->before")

    def test_a1(self, before):
        print("------->test_a1")
        assert 1

    # 一般用这种方式
    @pytest.mark.usefixtures("before")
    def test_a2(self):
        print("------->test_a2")
        assert 1


# --------------------------- 通过函数引用 函数级别 TestBBB类中每个测试方法执行前都会执行before_outter_class------------------------------
@pytest.fixture()
def before_outter_class():
    print("------->outter class before")


@pytest.mark.usefixtures("before_outter_class")
class TestBBB(object):
    def setup(self):
        print('-------classBBB setup')

    def test_b1(self):
        print("------->test_b1")
        assert 1

    def test_b2(self):
        print("------->test_b2")
        assert 1


# --------------------------- 设置为默认运行 函数级别 每个测试方法执行前都会自动执行------------------------------
@pytest.fixture(autouse=True)
def before_outter_class_c():
    print("------->outter class before ccccc")


class TestCCC(object):
    def setup(self):
        print('-------classCCC setup')

    def test_c(self):
        print("------->test_c")
        assert 1


# --------------------------- 设置作用域 默认是函数级别------------------------------
# class级别 TestDDD类中测试方法执行前执行一次before_outter_class_d()
@pytest.fixture(scope='class', autouse=True)
def before_outter_class_d():
    print("------->outter class before ddddd")


class TestDDD(object):
    def setup(self):
        print('-------classDDDD setup')

    def test_d1(self):
        print("------->test_d1")
        assert 1

    def test_d2(self):
        print("------->test_d2")
        assert 1


# --------------------------- 返回值------------------------------
@pytest.fixture(params=[1, 2, 3])
def need_data(request):
    return request.param


class TestABC(object):

    def test_abc(self, need_data):
        print("------->test_abc")
        # 拿到返回值做一次断言   会执行3次
        assert need_data != 2
    
    # 注意:@pytest.mark.usefixtures("need_data") 这种方式拿不到返回值
    @pytest.mark.usefixtures("need_data")
    def test_abc222(self):
        print("------->test_abc222")
        assert False
跳过测试函数

方法:
skipif(condition, reason=None)
参数:
condition:跳过的条件,必传参数
reason:标注原因,必传参数
使用方法:
@pytest.mark.skipif(condition, reason="xxx")

    # 跳过测试函数test_b
    @pytest.mark.skipif(condition=True, reason="就是不想执行")
    def test_b(self):
        print("------->test_b")
        assert 0
标记为预期失败函数

方法:
xfail(condition=None, reason=None, raises=None, run=True, strict=False)
常用参数:
condition:预期失败的条件,必传参数
reason:失败的原因,必传参数
使用方法:
@pytest.mark.xfail(condition, reason="xx")

    # 标记为预期失败函数test_c
    @pytest.mark.xfail(condition=2 > 1, reason="标注为预期失败")
    def test_c(self):
        print("------->test_c")
        assert 0
函数数据参数化

方法:
parametrize(argnames, argvalues, indirect=False, ids=None, scope=None)
常用参数:
argnames:参数名
argvalues:参数对应值,类型必须为list
当参数为一个值时格式:[value]
当参数个数大于一个时,格式为:[(param_value1,param_value2.....),(param_value1,param_value2.....)]
使用方法:
@pytest.mark.parametrize(argnames,argvalues)
⚠️ 参数值为N个,测试方法就会运行N次

# --------------------------- 单个参数 ---------------------------------
class TestAAA(object):
    def setup_class(self):
        print("------->setup_class")

    def teardown_class(self):
        print("------->teardown_class")

    @pytest.mark.parametrize("a", [3, 6])  # a参数被赋予两个值,函数会运行两遍
    def test_a(self, a):  # 参数必须和parametrize里面的参数一致
        print("test data:a=%d" % a)
        assert a % 3 == 0


# --------------------------- 多个参数 ---------------------------------
def get_test_data():
    return [(1, 2), (0, 3)]


class TestBBB:
    def setup_class(self):
        print("------->setup_class bbb")

    def teardown_class(self):
        print("------->teardown_class bbb")

    # 参数a,b均被赋予两组值,函数会运行两遍
    # @pytest.mark.parametrize("a,b", [(1, 2), (0, 3)])
    @pytest.mark.parametrize("a,b", get_test_data())
    # 参数必须和parametrize里面的参数一致
    def test_b(self, a, b):
        print("test data:a=%d,b=%d" % (a, b))
        assert a + b == 3
数据驱动
  • yaml
  1. yaml文件格式

语法规则
1.大小写敏感
2.使用缩进表示层级关系
3.缩进时不允许使用Tab键,只允许使用空格。
4.缩进的空格数目不重要,只要相同层级的元素左侧对齐即可

  1. 读取yaml文件
    yaml.load(stream, Loader=Loader)
with open("../resouce/data.yaml", 'r') as f:
    data = yaml.load(f, Loader=yaml.FullLoader)
    print(type(data))
    print(data)
  1. 写yaml文件
    yaml.dump(data,stream,**kwds)
    常用参数:
    data:写入数据类型为字典
    stream:打开文件对象
    encoding='utf-8' # 设置写入编码格式
    allow_unicode=True # 是否允许unicode编码
data = {'Search_Data': {
    'search_test_003': {'expect': {'value': '不好了'}, 'value': '着火了'},
    'search_test_004': {'expect': [8, 8, 6], 'value': 666}}}
with open("../resouce/data.yaml", "w") as f:
    yaml.dump(data, f, encoding='utf-8', allow_unicode=True)
  1. 锚点&和引用*
    锚点:标注一个内容,锚点名称自定义
    引用:使用被标注的内容<<: *锚点名
    data.yaml
     data: &imp
        value: 456
     name:
      value1: 123
      <<: *imp # "<<:" 合并到当前位置,"*imp" 引用锚点imp
    转换为python代码
     {'data': {'value': 456}, 'name': {'value': 456, 'value1': 123}}
生成测试报告
  • Allure
    Allure是一个独立的报告插件,生成美观易读的报告,目前支持语言:Java, PHP, Ruby, Python, Scala, C#。
    帮助文档:https://docs.qameta.io/allure/#_about
    生成Allure报告
    pytest --alluredir report # 在执行命令目录生成report文件夹,文件夹下包含xml文件
  • xml转html工具安装
  1. Mac版本
    (1)brew install allure
    (2)进入report上级目录执行命令:allure generate report/ -o report/html
    (3)report目录下会生成index.html文件,即为可视化报告
  2. windows版本
    (1)下载压缩包allure-2.5.0.zip 解压
    (2)将压缩包内的bin目录配置到path系统环境变量
    (3)进入report上级目录执行命令:allure generate report/ -o report/html
    (4)report目录下会生成index.html文件,即为可视化报告

添加测试步骤
@allure.step(title="测试步骤001")
添加测试描述
allure.attach('描述', '我是测试步骤001的描述~~~')
添加严重级别
@pytest.allure.severity(Severity)
参数 Severity:严重级别(BLOCKER,CRITICAL,NORMAL,MINOR,TRIVIAL)
使用方式:@pytest.allure.severity(pytest.allure.severity_level.CRITICAL)

test_all.py
        import allure, pytest
        class Test_allure:
            def setup(self):
                pass
            def teardown(self):
                pass
            @pytest.mark.parametrize("a",[1,2,3])
            @pytest.allure.severity(pytest.allure.severity_level.CRITICAL)
            @allure.step('我是测试步骤001')
            def test_al(self, a):
                allure.attach('描述', '我是测试步骤001的描述~~~')
                assert a != 2

allure严重级别.png

你可能感兴趣的:(pytest)