享受每一天,Just Enjoy !

0%

一篇文学会 Pytest 测试框架

之前有介绍过python自带的Unittest单元测试框架,Python 自动化测试实战 Zero to Hero 单元测试框架unittest的使用,今天再来简单的讲诉下测试框架pytest

本文首发自伊洛的个人博客:https://yiluotalk.com,欢迎关注并查看更多内容!!!
#####1. 安装开始

  • 直接使用pip安装就可以,pytest支持python2.03.0版本
    1
    2
    3
    4
    #!/usr/bin/python3
    # 伊洛Yiluo
    # https://yiluotalk.com
    pip install -U pytest
  • 检查版本,校验下是否安装成功
    1
    2
    3
    4
    #!/usr/bin/python3
    # 伊洛Yiluo
    # https://yiluotalk.com
    (yiluo) ➜ ~ pytest --version
    2. pytest的基础语法规范
  • 文件名应必须以test开头或结尾,例如test_example.pyexample_test.py
  • 如果将测试定义为类上的方法,类名应以“ Test”开头。例如,TestExample。且不包含__init__方法
  • 测试方法名称或函数名称应以test_开头,例如test_example,名称与该模式不匹配的方法将不会作为测试执行
  • 按照命名的约定举个例子
    1
    2
    3
    4
    5
    #!/usr/bin/python3
    # 伊洛Yiluo
    # https://yiluotalk.com
    - demo_tests/
    - test_example.py
    3. 开始测试
  • 例子1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #!/usr/bin/python3
    # 伊洛Yiluo
    # https://yiluotalk.com
    def func(x):
    return x + 1


    def test_answer():
    assert func(3) == 5
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #!/usr/bin/python3
    # 伊洛Yiluo
    # https://yiluotalk.com
    (yiluo) ➜ pytest pytest
    ======================== test session starts =========================
    platform darwin -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.13.1
    plugins: allure-pytest-2.8.6, rerunfailures-5.0
    collected 1 item

    test_sample.py F [100%]

    ============================== FAILURES ==============================
    ____________________________ test_answer _____________________________

    def test_answer():
    > assert func(3) == 5
    E assert 4 == 5
    E + where 4 = func(3)

    test_sample.py:6: AssertionError
    ========================= 1 failed in 0.05s ==========================
  • 例子2
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #!/usr/bin/python3
    # 伊洛Yiluo
    # https://yiluotalk.com
    import pytest


    def sum(num1, num2):
    return num1 + num2


    def test_sum():
    assert sum(3, 7) == 10
  • 运行查看结果
    1
    2
    3
    4
    5
    6
    7
    8
    9
    ================================== test session starts ==================================
    platform darwin -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.13.1

    plugins: allure-pytest-2.8.6, rerunfailures-5.0
    collected 1 item

    test_example.py . [100%]

    =================================== 1 passed in 0.01s ===================================
    1
    test_example.py .
  • 注意test_example.py .后面有一个点.,一个点就代表执行了一条测试用例
    执行多项测试
  • 如果需要获取更多信息的话,后面加上-v
    1
    2
    3
    4
    5
    collected 1 item                                                                        

    test_example.py::test_sum PASSED [100%]

    =================================== 1 passed in 0.01s ===================================
  • 再加一条用例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #!/usr/bin/python3
    # 伊洛Yiluo
    # https://yiluotalk.com
    import pytest


    def sum(num1, num2):
    return num1 + num2


    def test_sum():
    assert sum(3, 7) == 10


    def test_sum_output_type():
    assert type(sum(1, 2)) is int
  • 运行一下看下结果
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #!/usr/bin/python3
    # 伊洛Yiluo
    # https://yiluotalk.com
    collected 2 items

    test_example.py::test_sum PASSED [ 50%]
    test_example.py::test_sum_output_type PASSED [100%]

    =================================== 2 passed in 0.01s ===================================
  • 再试下用例执行不成功
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #!/usr/bin/python3
    # 伊洛Yiluo
    # https://yiluotalk.com
    import pytest


    def sum(num1, num2):
    return num1 + num2


    def test_sum():
    assert sum(3, 7) == 100


    def test_sum_output_type():
    assert type(sum(1, 2)) is int
  • 运行查看结果
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    test_example.py::test_sum FAILED                                                  [ 50%]
    test_example.py::test_sum_output_type PASSED [100%]

    ======================================= FAILURES ========================================
    _______________________________________ test_sum ________________________________________

    def test_sum():
    > assert sum(3, 7) == 100
    E assert 10 == 100
    E -10
    E +100

    test_example.py:12: AssertionError
    ============================== 1 failed, 1 passed in 0.06s ==============================
  • 例子3
  • 类的举例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #!/usr/bin/python3
    # 伊洛Yiluo
    # https://yiluotalk.com
    class TestClass(object):
    def test_one(self):
    x = 'Yiluo'
    assert 'l' in x

    def test_two(self):
    x = 'luoyi'
    assert hasattr(x, 'yiluo')
  • 运行结果
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    (yiluo) ➜  pytest pytest
    ======================== test session starts =========================
    platform darwin -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.13.1
    plugins: allure-pytest-2.8.6, rerunfailures-5.0
    collected 2 items

    test_class.py .F [100%]

    ============================== FAILURES ==============================
    _________________________ TestClass.test_two _________________________

    self = <test_class.TestClass object at 0x10c5af7d0>

    def test_two(self):
    x = 'luoyi'
    > assert hasattr(x, 'yiluo')
    E AssertionError: assert False
    E + where False = hasattr('luoyi', 'yiluo')

    test_class.py:8: AssertionError
    ==================== 1 failed, 1 passed in 0.06s =====================
    1
    2
    3
    4
    5
    6
    #!/usr/bin/python3
    # 伊洛Yiluo
    # https://yiluotalk.com
    - 用法和调用命令行还可以是

    python -m pytest [...]
4. 参数化测试
  • 让我们对test_sum函数进行更改以使用参数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #!/usr/bin/python3
    # 伊洛Yiluo
    # https://yiluotalk.com
    import pytest


    def sum(num1, num2):
    return num1 + num2


    @pytest.mark.parametrize('num1 , num2, expected', [(3, 5, 8)])
    def test_sum(num1, num2, expected):
    assert sum(num1, num2) == expected


    def test_sum_output_type():
    assert type(sum(1, 2)) is int
  • 运行查看结果
    1
    2
    3
    4
    5
    6
    collected 2 items                                                                       

    test_example.py::test_sum[3-5-8] PASSED [ 50%]
    test_example.py::test_sum_output_type PASSED [100%]

    =================================== 2 passed in 0.04s ===================================
  • 多传几个参数试验一下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #!/usr/bin/python3
    # 伊洛Yiluo
    # https://yiluotalk.com
    import pytest


    def sum(num1, num2):
    return num1 + num2


    @pytest.mark.parametrize('num1 , num2, expected', [(3, 5, 8),
    (-2, -2, -4), (6, 6, 12), (6, -1, 5), (0, 5, 5)])
    def test_sum(num1, num2, expected):
    assert sum(num1, num2) == expected


    def test_sum_output_type():
    assert type(sum(1, 2)) is int
  • 运行查看结果
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    collected 6 items                                                                       

    test_example.py::test_sum[3-5-8] PASSED [ 16%]
    test_example.py::test_sum[-2--2--4] PASSED [ 33%]
    test_example.py::test_sum[6-6-12] PASSED [ 50%]
    test_example.py::test_sum[6--1-5] PASSED [ 66%]
    test_example.py::test_sum[0-5-5] PASSED [ 83%]
    test_example.py::test_sum_output_type PASSED [100%]

    =================================== 6 passed in 0.03s ===================================
  • 我们还可以进行函数调用以获取这些值
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #!/usr/bin/python3
    # 伊洛Yiluo
    # https://yiluotalk.com
    import pytest


    def sum(num1, num2):
    return num1 + num2


    def get_sum_test_data():
    return [(3, 5, 8),
    (-2, -2, -4), (6, 6, 12), (6, -1, 5), (0, 5, 5)]


    @pytest.mark.parametrize('num1 , num2, expected', get_sum_test_data() )
    def test_sum(num1, num2, expected):
    assert sum(num1, num2) == expected


    def test_sum_output_type():
    assert type(sum(1, 2)) is int
  • 运行查看结果
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    collected 6 items                                                                       

    test_example.py::test_sum[3-5-8] PASSED [ 16%]
    test_example.py::test_sum[-2--2--4] PASSED [ 33%]
    test_example.py::test_sum[6-6-12] PASSED [ 50%]
    test_example.py::test_sum[6--1-5] PASSED [ 66%]
    test_example.py::test_sum[0-5-5] PASSED [ 83%]
    test_example.py::test_sum_output_type PASSED [100%]

    =================================== 6 passed in 0.02s ===================================
    5. Pytest之Fixture的使用
  • 用于在测试之间共享测试数据,分别在测试执行之前和之后执行设置方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    #!/usr/bin/python3
    # 伊洛Yiluo
    # https://yiluotalk.com
    import pytest


    def sum(num1, num2):
    return num1 + num2


    @pytest.fixture()
    def get_sum_test_data():
    return [(3, 5, 8),
    (-2, -2, -4), (6, 6, 12), (6, -1, 5), (0, 5, 5)]


    def test_sum(get_sum_test_data):
    for data in get_sum_test_data:
    num1 = data[0]
    num2 = data[1]
    expected = data[2]
    assert sum(num1, num2) == expected


    def test_sum_output_type():
    assert type(sum(1, 2)) is int
  • 执行查看结果
    1
    2
    3
    4
    5
    6
    collected 2 items                                                                       

    test_example.py::test_sum PASSED [ 50%]
    test_example.py::test_sum_output_type PASSED [100%]

    =================================== 2 passed in 0.03s ===================================
  • Scope of fixture
    function: 每次测试运行一次
    class: 每类测试运行一次
    module: 每个模块运行一次
    session: 每个会话运行一次
  • 权重
    function < class <module<session
  • autouse=True
    将默认使您套件中的每个测试都使用它
  • 例如1
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    #!/usr/bin/python3
    # 伊洛Yiluo
    # https://yiluotalk.com
    import pytest


    def sum(num1, num2):
    return num1 + num2


    @pytest.fixture(scope='session')
    def get_sum_test_data():
    return [(3, 5, 8),
    (-2, -2, -4), (6, 6, 12), (6, -1, 5), (0, 5, 5)]


    @pytest.fixture(autouse=True)
    def setup_and_teardown():
    print('\n获取数据')
    yield
    print('\n保存数据')


    def test_sum(get_sum_test_data):
    for data in get_sum_test_data:
    num1 = data[0]
    num2 = data[1]
    expected = data[2]
    assert sum(num1, num2) == expected


    def test_sum_output_type():
    assert type(sum(1, 2)) is int
  • 执行后查看结果 pytest test_example.py -v -s
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    collected 2 items                                                                       

    test_example.py::test_sum
    获取数据
    PASSED
    保存数据

    test_example.py::test_sum_output_type
    获取数据
    PASSED
    保存数据


    =================================== 2 passed in 0.02s ===================================
  • 例如2
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #!/usr/bin/python3
    # 伊洛Yiluo
    # https://yiluotalk.com
    import pytest

    @pytest.fixture()
    def setup():
    print('在测试之前')


    def test_one(setup):
    print('测试1')


    def test_two(setup):
    print('测试2')
    • 执行结果
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      (yiluo) ➜  pytest pytest -v -s fixture.py
      ======================== test session starts =========================
      platform darwin -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.13.1 --
      cachedir: .pytest_cache
      rootdir: /Users/joey/Code/pytest
      plugins: allure-pytest-2.8.6, rerunfailures-5.0
      collected 2 items

      fixture.py::test_one 在测试之前
      测试1
      PASSED
      fixture.py::test_two 在测试之前
      测试2
      PASSED

      ========================= 2 passed in 0.01s ==========================
  • fixture 返回值
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import pytest


    @pytest.fixture(params=[1, 2, 3])
    def test_data(request):
    return request.param


    def test_assert_all(test_data):
    print('test_data: %s' % test_data)
    assert test_data != 5
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    (yiluo) ➜  pytest pytest -v -s fixture_param.py
    ======================== test session starts =========================
    platform darwin -- Python 3.7.5, pytest-5.3.2, py-1.8.0, pluggy-0.13.1 -- /Users/joey/yiluo/bin/python3
    cachedir: .pytest_cache
    plugins: allure-pytest-2.8.6, rerunfailures-5.0
    collected 3 items

    fixture_param.py::test_assert_all[1] test_data: 1
    PASSED
    fixture_param.py::test_assert_all[2] test_data: 2
    PASSED
    fixture_param.py::test_assert_all[3] test_data: 3
    PASSED

    ========================= 3 passed in 0.01s ==========================
6. pytest.mark
  • skip — 跳过测试功能
  • skipif — 如果满足特定条件,则跳过测试功能
  • xfail — 如果满足特定条件,则会产生“预期的失败”结果
  • parametrize执行对同一测试功能的多次调用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #!/usr/bin/python3
    # 伊洛Yiluo
    # https://yiluotalk.com
    import pytest


    def sum(num1, num2):
    return num1 + num2


    @pytest.mark.skip
    def test_sum():
    assert sum(3, 7) == 10


    def test_sum_output_type():
    assert type(sum(1, 2)) is int
  • 执行查看结果
    1
    2
    3
    4
    5
    6
    collected 2 items                                                                       

    test_example.py::test_sum SKIPPED [ 50%]
    test_example.py::test_sum_output_type PASSED [100%]

    ============================= 1 passed, 1 skipped in 0.01s ==============================
  • 成功跳过测试用例
  • 运行的方式

    名称中带有“ validate”字符串的所有测试
    pytest -k “validate”
    排除名称中带有“ db”的测试,但包括“ validate”
    pytest -k “validate and not db”
    运行文件夹demo_tests中的所有测试文件
    pytest demo_tests/
    运行测试类TestClassDemo的单个方法test_method
    pytest demo_tests/test_example.py::TestClassDemo::test_method
    运行一个名为TestClassDemo的测试类
    pytest demo_tests/test_example.py::TestClassDemo
    运行一个名为test_sum的测试函数
    pytest demo_tests/test_example.py::test_sum
    以详细模式运行测试
    pytest -v demo_tests/
    运行包括打印语句的测试
    pytest -s demo_tests/
    仅运行上次运行失败的测试
    pytest — lf

在这里插入图片描述

欢迎下方【戳一下】【点赞】
Author:伊洛Yiluo
愿你享受每一天,Just Enjoy !

关注公众号获取更多内容