精华内容
下载资源
问答
  • pytest

    2020-02-24 23:30:49
    pytest

    高质量的测试是很多良好编程实践比如 TDD、重构以及持续集成等的基本功,也是敏捷软件开发,DevOps 等方法论落地的安全网,更是目前招聘市场对工程师技能考核的重要一环。

    很多一线工程师甚至打趣道,先有测试,后有天。

    Pytest 作为现今最流行的 Python 测试框架在实际项目中被广泛使用,本文着重介绍如何使用 Pytest 编写测试代码, 内容包括但不限于:

    • Pytest 的安装及配置
    • Pytest 的基本方法
    • Pytest Fixture
    • Pytest Conftest.py
    • Pytest 参数化测试

    Pytest 简介及安装方法

    Pytest 是一款基于 Python 的测试框架,可以用来编写和运行测试代码。

    优势:

    • Pytest 可以并发执行多个测试,节约测试时间
    • 测试函数嗅探
    • 运行测试时可以选择性跳过部分测试
    • 可以指定部分测试运行
    • 免费且开源
    • 语法简单,入门容易

    安装方法

    需要确保 Python 已经被成功安装:

    pip install pytest

    查看 Pytest 是否安装成功:

    ➜python pytest -v=========== test session starts ==============platform linux -- Python 3.6.8, pytest-5.3.1, py-1.8.0

    Pytest 基本用法

    Pytest 的测试函数需要以 test 开头:

    运行测试脚本

    # Filename test1.pyimport mathdef test_sqrt():   num = 49   assert math.sqrt(num) == 7def testsquare():   num = 7   assert 7*7 == 88def tesequality(): # 函数不是以 test 开头,pytest 识别不到   assert 10 == 11

    执行测试:

    pytest test1

    输出:

    ➜  python pytest test1.py=== test session starts ===platform linux -- Python 3.6.8, pytest-5.3.1, py-1.8.0, pluggy-0.13.1rootdir: /mnt/f/pythoncollected 2 items                   test1.py .F                      [100%]=== FAILURES ===___ testsquare ____    def testsquare():       num = 7>      assert 7*7 == 88E      assert (7 * 7) == 88test1.py:11: AssertionError==== 1 failed, 1 passed in 0.03s === # 识别到两个测试函数,一个成功,一个测试失败

    可见没有以 test 开头的测试函数并没有被识别,已识别的函数中一个成功,一个测试失败了。

    使用 -v 参数可以看到更详细的输出:

    pytest -v test1

    输出

    ➜  python pytest -v test1.py=== test session starts ===platform linux -- Python 3.6.8, pytest-5.3.1, py-1.8.0, pluggy-0.13.1 -- /usr/bin/python3cachedir: .pytest_cacherootdir: /mnt/f/pythoncollected 2 items       test1.py::test_sqrt PASSED       [ 50%] # 详细输出test1.py::testsquare FAILED      [100%] # 详细输出=== FAILURES ===___ testsquare ___    def testsquare():       num = 7>      assert 7*7 == 88E      assert 49 == 88E        -49E        +88test1.py:11: AssertionError=== 1 failed, 1 passed in 0.03s ===

    指定测试函数

    python pytest test1.py -k testsquare -v

    输出:

    ➜  python pytest test1.py -k testsquare -v=== test session starts ===platform linux -- Python 3.6.8, pytest-5.3.1, py-1.8.0, pluggy-0.13.1 -- /usr/bin/python3cachedir: .pytest_cacherootdir: /mnt/f/pythoncollected 2 items / 1 deselected / 1 selected      test1.py::testsquare FAILED     [100%]=== FAILURES ===___ testsquare ___    def testsquare():       num = 7>      assert 7*7 == 88E      assert 49 == 88E        -49E        +88test1.py:11: AssertionError=== 1 failed, 1 deselected in 0.03s ===

    Pytest - Fixtures

    fixture 本身就是函数,会在测试函数运行前执行。fixture 可以用来准备测试数据,比如数据库链接,URL ,或者是某些输入数据。所以被反复使用的某些测试数据可以使用 fixture 来构造以减少重复代码。语法糖如下:

    @pytest.fixture

    代码示例:

    import pytest@pytest.fixturedef input_value():   input = 39   return inputdef test_divisible_by_3(input_value):   assert input_value % 3 == 0def test_divisible_by_6(input_value):   assert input_value % 6 == 0

    fixture 的局限性在于它只在被定义的测试文件内有效,我们无法使用某个脚本内的 fixture 作用于另一个测试脚本,为了使 fixture 可以跨脚本生效,需要把相关 fixture 定义在 conftest.py 文件中。

    Pytest - conftest.py

    把 fixture 定义到 conftest.py 中,可以跨脚本生效,我们来举例说明:

    首先,我们新建一个 conftest.py 文件

    # Filename conftest.py import pytest@pytest.fixturedef input_value():   input = 39   return input

    接着,我们创建测试脚本 testdivby36.py ,该脚本包含两个测试函数,一个测试输入数据否能被 3 整除,一个测试输入数据是否能被 6 整除:

    # Filename test_div_by_3_6.pyimport pytestdef test_divisible_by_3(input_value):   assert input_value % 3 == 0def test_divisible_by_6(input_value):   assert input_value % 6 == 0

    然后,我们再创建一个测试脚本 testdivby_13.py ,该脚本包含一个测试函数,测试输入数据能否被 13 整除。

    # Filename test_div_by_13.pyimport pytestdef test_divisible_by_13(input_value):   assert input_value % 13 == 0

    总体脚本结构如下:file structure运行测试:

    pytest -k divisible -v

    输出:

    ➜  python pytest -k divisible -v=== test session starts ===platform linux -- Python 3.6.8, pytest-5.3.1, py-1.8.0, pluggy-0.13.1 -- /usr/bin/python3cachedir: .pytest_cacherootdir: /mnt/f/pythoncollected 3 items   test_div_by_13.py::test_divisible_by_13 PASSED      [ 33%]test_div_by_3_6.py::test_divisible_by_3 PASSED      [ 66%]test_div_by_3_6.py::test_divisible_by_6 FAILED      [100%]=== FAILURES ===___ test_divisible_by_6 ___input_value = 39    def test_divisible_by_6(input_value):>      assert input_value % 6 == 0E      assert 3 == 0E        -3E        +0test_div_by_3_6.py:7: AssertionError=== 1 failed, 2 passed in 0.04s ===

    可见 conftest.py 的 fixture ( 输入数据 39 ),被所有不同文件中的测试函数成功接收并都按照预期执行,给出了相关测试结果。

    Pytest - 参数化测试

    参数化测试(Parameterizing),就是向同一测试函数中传递多个不同的测试参数组合,语法糖:

    @pytest.mark.parametrize

    使用举例:

    import pytest@pytest.mark.parametrize("num, output",[(1,11),(2,22),(3,35),(6,66)])def test_multiplication_11(num, output):   assert 11*num == output

    执行测试:

    pytest -k multiplication -v

    输出:

    ➜  python pytest -k multiplication -v=== test session starts ===platform linux -- Python 3.6.8, pytest-5.3.1, py-1.8.0, pluggy-0.13.1 -- /usr/bin/python3cachedir: .pytest_cacherootdir: /mnt/f/pythoncollected 7 items / 3 deselected / 4 selected                                                                                                                                                test_multiplication.py::test_multiplication_11[1-11] PASSED     [ 25%]test_multiplication.py::test_multiplication_11[2-22] PASSED     [ 50%]test_multiplication.py::test_multiplication_11[3-35] FAILED     [ 75%]test_multiplication.py::test_multiplication_11[6-66] PASSED     [100%]=== FAILURES ===___ test_multiplication_11[3-35] ___num = 3, output = 35    @pytest.mark.parametrize("num, output",[(1,11),(2,22),(3,35),(6,66)])    def test_multiplication_11(num, output):>      assert 11*num == outputE      assert 33 == 35E        -33E        +35test_multiplication.py:5: AssertionError=== 1 failed, 3 passed, 3 deselected in 0.06s ===

    由此就实现向同一测试函数传递不同的测试数据组合,以减少重复代码。

    Xfail/Skip Tests

    为了使测试函数管理更加灵活,Pytest 支持我们手动标记测试函数为 Xfail 或者 skip 。

    如果一个测试函数被标记成 Xfail ,那么该函数会执行,但无论测试结果成功或失败,都不会有详细的日志输出,其语法糖为:

    @pytest.mark.xfail

    代码示例:

    import pytest@pytest.mark.xfaildef test_greater():   num = 100   assert num > 100@pytest.mark.xfaildef test_greater_equal():   num = 100   assert num >= 100

    输出:

    ➜  python pytest -k greater -v=== test session starts ===platform linux -- Python 3.6.8, pytest-5.3.1, py-1.8.0, pluggy-0.13.1 -- /usr/bin/python3cachedir: .pytest_cacherootdir: /mnt/f/pythoncollected 10 items / 8 deselected / 2 selected    # XFAIL 与标准 FAILED 不同,不会有详细日志输出test_compare.py::test_greater XFAIL           [ 50%] test_compare.py::test_greater_equal XPASS     [100%]=== 8 deselected, 1 xfailed, 1 xpassed in 0.05s ===

    相比之下 skip 就很好理解,标记 skip 的测试函数会被跳过不予执行,其语法糖为:

    @pytest.mark.skip

    代码示例:

    import pytest@pytest.mark.xfaildef test_greater():   num = 100   assert num > 100@pytest.mark.skip # 标记 skipdef test_greater_equal():   num = 100   assert num >= 100

    输出:

    ➜  python pytest -k greater -v=== test session starts ===platform linux -- Python 3.6.8, pytest-5.3.1, py-1.8.0, pluggy-0.13.1 -- /usr/bin/python3cachedir: .pytest_cacherootdir: /mnt/f/pythoncollected 10 items / 8 deselected / 2 selected    test_compare.py::test_greater XFAIL               [ 50%]test_compare.py::test_greater_equal SKIPPED       [100%]=== 1 skipped, 8 deselected, 1 xfailed in 0.05s ===

    测试失败容忍度

    从上面的例子中,你可能会观察到默认情况下 Pytest 会执行所有相关的测试,并在测试完成后汇总测试结果,输出日志信息。

    如果你的代码要部署到生产环境,原则上任何单元测试都不允许失败。那么如何让测试运行途中一旦发现失败就马上停止运行并输出日志呢?

    # maxfail 指定可以接受的最多失败测试个数,一旦达到,立即终止运行,输出日志pytest --maxfail = <num>

    代码示例:

    # Filename test_failure.pyimport pytestimport mathdef test_sqrt_failure():   num = 25   assert math.sqrt(num) == 88def test_square_failure():   num = 7   assert 7*7 == 99def test_equality_failure():   assert 10 == 66

    运行测试:

    pytest test_failure.py -v --maxfail=1

    输出:

    ➜  python pytest test_failure.py -v --maxfail=1=== test session starts ===platform linux -- Python 3.6.8, pytest-5.3.1, py-1.8.0, pluggy-0.13.1 -- /usr/bin/python3cachedir: .pytest_cacherootdir: /mnt/f/pythoncollected 3 items    test_failure.py::test_sqrt_failure FAILED   [ 33%]=== FAILURES ===___ test_sqrt_failure ___    def test_sqrt_failure():       num = 25>      assert math.sqrt(num) == 88E      assert 5.0 == 88E        -5.0E        +88test_failure.py:6: AssertionError!!! stopping after 1 failures !!!=== 1 failed in 0.04s ===

    高级特性

    并发执行测试

    如果你有大量的测试需要完成,那么并发执行是一个很好的方式。

    并发执行测试,你需要 pytest-xdist 插件,安装方法如下:

    pip install pytest-xdist

    执行方法:

    # -n 3 同时会有三个任务并发执行pytest -n 3

    把测试结果存入 XML 文件中

    把测试结果存入 XML 文件中方便测试数据的可视化展示,用法如下:

    # --junitxml 指定输出 XML 文件名pytest test_multiplication.py -v --junitxml='test_result.xml'

    Pytest 良好实践

    高质量的测试对于软件产品质量的重要性不言而喻,现今诸多流行的编程实践皆以测试为基础,比如测试驱动开发(TDD),持续集成(CI)等。

    关于 Pytest 的使用,几条推荐良好实践是:

    • 针对不同的功能或模块,定义相对应的测试脚本。
    • 测试函数命名清晰明了。
    • 善用 fixture 减少重复代码。

    更多 Python 及云计算相关技术问题,欢迎添加我的个人微信 chen5640 一起讨论学习。

    阅读全文: http://gitbook.cn/gitchat/activity/5e5316ed98a13e1481f36953

    您还可以下载 CSDN 旗下精品原创内容社区 GitChat App ,阅读更多 GitChat 专享技术内容哦。

    FtooAtPSkEJwnW-9xkCLqSTRpBKX

    展开全文
  • Pytest

    2020-09-17 21:50:44
    pytest 在pycharm中安装pytest:pip install pytest 安装pytest自带的测试报告包: pip install pytest-html 配置allure 在系统变量path中添加:对应的allure安装路径 验证是否配置成功 成功的标志是: 命名规则 ...

    pytest

    在pycharm中安装pytest:pip install pytest
    在这里插入图片描述
    安装pytest自带的测试报告包: pip install pytest-html
    在这里插入图片描述
    配置allure

    在系统变量path中添加:对应的allure安装路径
    在这里插入图片描述
    验证是否配置成功
    成功的标志是:
    在这里插入图片描述

    命名规则 Pytest单元测试中的类名和方法名必须是以test开头,执行中只能找到test开头的类和方法,比unittest更加严谨

    unittest:Setup>> setupclass teardown teardownclass
    Pytest的setup, setup_class和teardown, teardown_class函数(和unittest执行效果一样)
    运行于测试方法的始末,即:运行一次测试函数会运行一次setup和teardown
    运行于测试方法的始末,但是不管有多少测试函数都只执行一次setup_class和 teardown_class

    Pytest生成自带的html测试报告

    直接执行pytest.main()
    【自动查找当前目录下,以test_开头的文件或者以_test结尾的py文件】(课堂练习_test)
    pytest.main(“模块.py”)
    【运行指定模块下,运行所有test开头的类和测试用例】
    pip install pytest-html() :python自带的插件
    pytest.main(["–html=./report.html",“test3.py”])

    Pytest 调用语句

    pytest.main([‘–html=./report.html’,‘模块.py::类::test_a_001’])
    运行指定模块指定类指定用例,冒号分割,并生成测试报告

    pytest.main([’-x’,’–html=./report.html’,‘t12est000.py’])
    #-x出现一条测试用例失败就退出测试

    -v: 丰富信息模式, 输出更详细的用例执行信息
    -s:显示print内容
    -q: 简化结果信息,不会显示每个用例的文件名

    作业

    1. 先写一个方法

    class Calc():
    def add(self,a,b):
    c = a+b
    return c
    def jian(self,a,b):
    c = a-b
    return c
    a = Calc()
    c = a.jian(3,2)
    print©

    在这里插入图片描述

    1. 验证方法是否正确

    正确的情况下
    import pytest #导入pytest模块
    from funcDemo.Calc import Calc #将上一步方法导入进来
    class TestClass():#创建一个类
    def setup(self):
    print(‘setup…start’)
    def setup_class(self):
    print(‘setup_class…start’)
    def test001(self):#调用加法
    c = Calc()
    a = c.add(1,2)
    assert a == 3
    def test002(self):#调用减法
    c = Calc()
    a = c.jian(2,3)
    assert a == -1
    def teardown(self):
    print(‘teardown…end’)
    def teardown_class(self):
    print(‘teardown_class…end’)
    if name == ‘main’:
    pytest.main([’-s’,"–html=./report.html",“test1.py::TestClass::test002”])

    在这里插入图片描述
    在这里插入图片描述

    1. 错误的情况下
      在这里插入图片描述
      在这里插入图片描述
    2. 只运行一个函数方法
      在这里插入图片描述
      在这里插入图片描述
    3. 生成测试报告
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
    展开全文
  • Pytest】python单元测试框架pytest简介

    万次阅读 多人点赞 2015-06-15 11:41:16
    1、Pytest介绍 pytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高。根据pytest的官方网站介绍,它具有如下特点: 非常容易上手,入门简单,...

    最新更新请看 《基于Pytest框架的自动化测试开发实践(万字长文入门篇)》

    1、Pytest介绍

    pytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高。根据pytest的官方网站介绍,它具有如下特点:

     

    • 非常容易上手,入门简单,文档丰富,文档中有很多实例可以参考
    • 能够支持简单的单元测试和复杂的功能测试
    • 支持参数化
    • 执行测试过程中可以将某些测试跳过,或者对某些预期失败的case标记成失败
    • 支持重复执行失败的case
    • 支持运行由nose, unittest编写的测试case
    • 具有很多第三方插件,并且可以自定义扩展
    • 方便的和持续集成工具集成
    由于网上pytest的中文文档比较少,自己学习过程中,基本上看的就是英文的官方文档,对于不想看英文的同学们,本系列文章希望能够帮大家一马。
     

    2、安装pytest

    与安装其他的python软件无异,直接使用pip安装。
    pip install -U pytest
    安装完成后,可以验证安装的版本:
    py.test --version
     

    3、一个实例

    我们可以通过下面的实例,看看使用py.test进行测试是多么简单。
    # content of test_sample.py
    
    def func(x):
        return x+1
    
    def test_func():
        assert func(3) == 5
    这里我们定义了一个被测试函数func,该函数将传递进来的参数加1后返回。我们还定义了一个测试函数test_func用来对func进行测试。test_func中我们使用基本的断言语句assert来对结果进行验证。
    下面来运行这个测试:
    $ py.test
    =========================== test session starts ============================
    platform linux -- Python 3.4.1 -- py-1.4.27 -- pytest-2.7.1
    rootdir: /tmp/doc-exec-101, inifile:
    collected 1 items
    test_sample.py F
    ================================= FAILURES =================================
    _______________________________ test_answer ________________________________
    def test_answer():
    > assert func(3) == 5
    E assert 4 == 5
    E + where 4 = func(3)
    test_sample.py:5: AssertionError
    ========================= 1 failed in 0.01 seconds =========================
    执行测试的时候,我们只需要在测试文件test_sample所在的目录下,运行py.test即可。pytest会在当前的目录下,寻找以test开头的文件(即测试文件),找到测试文件之后,进入到测试文件中寻找test_开头的测试函数并执行。
    通过上面的测试输出,我们可以看到该测试过程中,一个收集到了一个测试函数,测试结果是失败的(标记为F),并且在FAILURES部分输出了详细的错误信息,帮助我们分析测试原因,我们可以看到"assert func(3) == 5"这条语句出错了,错误的原因是func(3)=4,然后我们断言func(3) 等于 5。
     

    4、再一个实例

    当需要编写多个测试样例的时候,我们可以将其放到一个测试类当中,如:
    # content of test_class.py
    
    class TestClass:
        def test_one(self):
            x = "this"
            assert 'h' in x
    
        def test_two(self):
            x = "hello"
            assert hasattr(x, 'check')
    
    我们可以通过执行测试文件的方法,执行上面的测试:
    $ py.test -q test_class.py
    .F
    ================================= FAILURES =================================
    ____________________________ TestClass.test_two ____________________________
    self = <test_class.TestClass object at 0x7fbf54cf5668>
    def test_two(self):
    x = "hello"
    > assert hasattr(x, 'check')
    E assert hasattr('hello', 'check')
    test_class.py:8: AssertionError
    1 failed, 1 passed in 0.01 seconds
    
    从测试结果中可以看到,该测试共执行了两个测试样例,一个失败一个成功。同样,我们也看到失败样例的详细信息,和执行过程中的中间结果。
     

    5、如何编写pytest测试样例

    通过上面2个实例,我们发现编写pytest测试样例非常简单,只需要按照下面的规则:
    • 测试文件以test_开头(以_test结尾也可以)
    • 测试类以Test开头,并且不能带有 __init__ 方法
    • 测试函数以test_开头
    • 断言使用基本的assert即可

    6、如何执行pytest测试样例

    执行测试样例的方法很多种,上面第一个实例是直接执行py.test,第二个实例是传递了测试文件给py.test。其实py.test有好多种方法执行测试:
    py.test               # run all tests below current dir
    py.test test_mod.py   # run tests in module
    py.test somepath      # run all tests below somepath
    py.test -k stringexpr # only run tests with names that match the
                          # the "string expression", e.g. "MyClass and not method"
                          # will select TestMyClass.test_something
                          # but not TestMyClass.test_method_simple
    py.test test_mod.py::test_func # only run tests that match the "node ID",
    			       # e.g "test_mod.py::test_func" will select
                                   # only test_func in test_mod.py

    7、测试报告

    pytest可以方便的生成测试报告,即可以生成HTML的测试报告,也可以生成XML格式的测试报告用来与持续集成工具集成。

    生成HTML格式报告:

     

    py.test --resultlog=path
    生成XML格式的报告:

     

     

    py.test --junitxml=path

     

    8、如何获取帮助信息

    py.test --version # shows where pytest was imported from
    py.test --fixtures # show available builtin function arguments
    py.test -h | --help # show help on command line and config file options
    

    9、最佳实践

    其实对于测试而言,特别是在持续集成环境中,我们的所有测试最好是在虚拟环境中。这样不同的虚拟环境中的测试不会相互干扰的。
    由于我们的实际工作中,在同一个Jekins中,运行了好多种不同项目册的测试,因此,各个测试项目运行在各自的虚拟环境中。
    将pytest安装在虚拟环境中:
    1、将当前目录创建为虚拟环境
    virtualenv .        # create a virtualenv directory in the current directory
    source bin/activate # on unix
    
    2、在虚拟环境中安装pytest:
    pip install pytest


     
     

     

    展开全文
  • pytest最新文档

    2017-07-31 14:51:29
    pytest
  • Python测试框架之pytest详解

    万次阅读 多人点赞 2019-08-09 13:16:41
    Python测试框架之前一直用的是unittest+HTMLTestRunner,听到有人说pytest很好用,所以这段时间就看了看pytest文档,在这里做个记录。 官方文档介绍: Pytest is a framework that makes building simple and ...

    前言

    Python测试框架之前一直用的是unittest+HTMLTestRunner,听到有人说pytest很好用,所以这段时间就看了看pytest文档,在这里做个记录。

    官方文档介绍:

    Pytest is a framework that makes building simple and scalable tests easy. Tests are expressive and readable—no boilerplate code required. Get started in minutes with a small unit test or complex functional test for your application or library.

    pytest是一个非常成熟的全功能的Python测试框架,主要有以下几个特点:

    • 简单灵活,容易上手
    • 支持参数化
    • 能够支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试、接口自动化测试(pytest+requests)
    • pytest具有很多第三方插件,并且可以自定义扩展,比较好用的如pytest-selenium(集成selenium)、pytest-html(完美html测试报告生成)、pytest-rerunfailures(失败case重复执行)、pytest-xdist(多CPU分发)等
    • 测试用例的skip和xfail处理
    • 可以很好的和jenkins集成
    • report框架----allure 也支持了pytest

    1、pytest安装

    1.1安装

    pip install -U pytest

    1.2验证安装

    pytest --version # 会展示当前已安装版本

    1.3pytest文档

    官方文档:https://docs.pytest.org/en/latest/contents.html

    在pytest框架中,有如下约束:

    所有的单测文件名都需要满足test_*.py格式或*_test.py格式。
    在单测文件中,测试类以Test开头,并且不能带有 init 方法(注意:定义class时,需要以T开头,不然pytest是不会去运行该class的)
    在单测类中,可以包含一个或多个test_开头的函数。
    此时,在执行pytest命令时,会自动从当前目录及子目录中寻找符合上述约束的测试函数来执行。

    1.4 Pytest运行方式

     # file_name: test_abc.py
     import pytest # 引入pytest包
     def test_a(): # test开头的测试函数
         print("------->test_a")
         assert 1 # 断言成功
     def test_b():
         print("------->test_b")
         assert 0 # 断言失败
     if __name__ == '__main__':
            pytest.main("-s  test_abc.py") # 调用pytest的main函数执行测试
    

    1.测试类主函数模式

      pytest.main("-s  test_abc.py")
    

    2.命令行模式

      pytest 文件路径/测试文件名
      例如:pytest ./test_abc.py
    

    1.5 Pytest Exit Code 含义清单

    • Exit code 0 所有用例执行完毕,全部通过
    • Exit code 1 所有用例执行完毕,存在Failed的测试用例
    • Exit code 2 用户中断了测试的执行
    • Exit code 3 测试执行过程发生了内部错误
    • Exit code 4 pytest 命令行使用错误
    • Exit code 5 未采集到可用测试用例文件

    1.6 如何获取帮助信息

    查看 pytest 版本

    pytest --version
    

    显示可用的内置函数参数

    pytest --fixtures
    

    通过命令行查看帮助信息及配置文件选项

    pytest --help
    

    1.7 控制测试用例执行

    1.在第N个用例失败后,结束测试执行

    pytest -x                    # 第01次失败,就停止测试
    pytest --maxfail=2     # 出现2个失败就终止测试
    

    2.指定测试模块

    pytest test_mod.py
    

    3.指定测试目录

    pytest testing/
    

    4.通过关键字表达式过滤执行

    pytest -k "MyClass and not method"
    

    这条命令会匹配文件名、类名、方法名匹配表达式的用例,这里这条命令会运行 TestMyClass.test_something, 不会执行 TestMyClass.test_method_simple

    5.通过 node id 指定测试用例

    nodeid由模块文件名、分隔符、类名、方法名、参数构成,举例如下:
    运行模块中的指定用例

    pytest test_mod.py::test_func
    

    运行模块中的指定方法

    ytest test_mod.py::TestClass::test_method
    

    6.通过标记表达式执行

    pytest -m slow
    

    这条命令会执行被装饰器 @pytest.mark.slow 装饰的所有测试用例

    7.通过包执行测试

    pytest --pyargs pkg.testing
    

    这条命令会自动导入包 pkg.testing,并使用该包所在的目录,执行下面的用例。

    1.8 多进程运行cases

    当cases量很多时,运行时间也会变的很长,如果想缩短脚本运行的时长,就可以用多进程来运行。

    安装pytest-xdist:

    pip install -U pytest-xdist
    

    运行模式:

    pytest test_se.py -n NUM
    

    其中NUM填写并发的进程数。

    1.9 重试运行cases

    在做接口测试时,有事会遇到503或短时的网络波动,导致case运行失败,而这并非是我们期望的结果,此时可以就可以通过重试运行cases的方式来解决。

    安装pytest-rerunfailures:

    pip install -U pytest-rerunfailures
    

    运行模式:

    pytest test_se.py --reruns NUM
    

    NUM填写重试的次数。

    1.10 显示print内容

    在运行测试脚本时,为了调试或打印一些内容,我们会在代码中加一些print内容,但是在运行pytest时,这些内容不会显示出来。如果带上-s,就可以显示了。

    运行模式:

    pytest test_se.py -s
    

    另外,pytest的多种运行模式是可以叠加执行的,比如说,你想同时运行4个进程,又想打印出print的内容。可以用:

    pytest test_se.py -s -n 4
    

     

    2.Pytest的setup和teardown函数

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

    • 函数级别setup()/teardown()

    运行于测试方法的始末,即:运行一次测试函数会运行一次setup和teardown

    import pytest
    class Test_ABC:
      # 函数级开始
      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")
    if __name__ == '__main__':
                  pytest.main("-s  test_abc.py")
    
    执行结果:
      test_abc.py 
      ------->setup_method # 第一次 setup()
      ------->test_a
      .
      ------->teardown_method # 第一次 teardown()
      ------->setup_method # 第二次 setup()
      ------->test_b
      .
              ------->teardown_method # 第二次 teardown()
    
    • 2.2.类级别

    运行于测试类的始末,即:在一个测试内只运行一次setup_class和teardown_class,不关心测试类内有多少个测试函数。
    代码示例:

    import pytest
    class Test_ABC:
       # 测试类级开始
       def setup_class(self):
           print("------->setup_class")
       # 测试类级结束
       def teardown_class(self):
           print("------->teardown_class")
       def test_a(self):
           print("------->test_a")
           assert 1
       def test_b(self):
           print("------->test_b")
              if __name__ == '__main__':
                  pytest.main("-s  test_abc.py")
    
    执行结果:
      test_abc.py 
      ------->setup_class # 第一次 setup_class()
      ------->test_a
      .
      ------->test_b
      F 
              ------->teardown_class # 第一次 teardown_class()
    

    3.Pytest配置文件

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

    #配置pytest命令行运行参数
       [pytest]
        addopts = -s ... # 空格分隔,可添加多个命令行参数 -所有参数均为插件包的参数配置测试搜索的路径
        testpaths = ./scripts  # 当前目录下的scripts文件夹 -可自定义
    #配置测试搜索的文件名称
        python_files = test*.py 
    #当前目录下的scripts文件夹下,以test开头,以.py结尾的所有文件 -可自定义
    配置测试搜索的测试类名
        python_classes = Test_*  
    
       #当前目录下的scripts文件夹下,以test开头,以.py结尾的所有文件中,以Test开头的类 -可自定义
    配置测试搜索的测试函数名
      
        python_functions = test_*
    
    #当前目录下的scripts文件夹下,以test开头,以.py结尾的所有文件中,以Test开头的类内,以test_开头的方法 -可自定义
    
    

    4 Pytest常用插件

    插件列表网址:https://plugincompat.herokuapp.com
    包含很多插件包,大家可依据工作的需求选择使用。

    4.1 前置条件:

    1.文件路径:

    - Test_App
    - - test_abc.py
    - - pytest.ini
    

    2.pyetst.ini配置文件内容:

      [pytest]
    # 命令行参数
     addopts = -s
    # 搜索文件名
     python_files = test_*.py
     # 搜索的类名
     python_classes = Test_*
     #搜索的函数名
        python_functions = test_*
    

    4.2 Pytest测试报告

    pytest-HTML是一个插件,pytest用于生成测试结果的HTML报告。兼容Python 2.7,3.6

    安装方式:pip install pytest-html

    pip install pytest-html

    通过命令行方式,生成xml/html格式的测试报告,存储于用户指定路径。插件名称:pytest-html

    使用方法: 命令行格式:pytest --html=用户路径/report.html

    示例:

    import pytest
    class Test_ABC:
        def setup_class(self):
            print("------->setup_class")
        def teardown_class(self):
            print("------->teardown_class")
        def test_a(self):
            print("------->test_a")
            assert 1
        def test_b(self):
                print("------->test_b")
                assert 0 # 断言失败```
    运行方式:
    1.修改Test_App/pytest.ini文件,添加报告参数,即:addopts = -s --html=./report.html 
        # -s:输出程序运行信息
        # --html=./report.html 在当前目录下生成report.html文件
        ️ 若要生成xml文件,可将--html=./report.html 改成 --html=./report.xml
    2.命令行进入Test_App目录
    3.执行命令: pytest
    执行结果:
        1.在当前目录会生成assets文件夹和report.html文件
    
    

    5.pytest的高阶用法(一)

    前置条件:

    1.文件路径:

    Test_App
        - - test_abc.py
        - - pytest.ini
    

    2.pyetst.ini配置文件内容:

    
    [pytest]
      命令行参数
     addopts = -s
     搜索文件名
     python_files = test*.py
      搜索的类名
     python_classes = Test*
    搜索的函数名
     python_functions = test_*
    

    5.1pytest之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自动运行
    

    5.2fixture第一个例子(通过参数引用)

    示例:

    class Test_ABC:
        @pytest.fixture()
        def before(self):
            print("------->before")
        def test_a(self,before): # ️ test_a方法传入了被fixture标识的函数,已变量的形式
            print("------->test_a")
            assert 1
    if __name__ == '__main__':
        pytest.main("-s  test_abc.py")
    执行结果:
        test_abc.py 
            ------->before # 发现before会优先于测试函数运行
            ------->test_a
             .
    

    5.3.fixture第二个例子(通过函数引用)

    示例:

    import pytest
    @pytest.fixture() # fixture标记的函数可以应用于测试类外部
    def before():
        print("------->before")
    @pytest.mark.usefixtures("before")
    class Test_ABC:
        def setup(self):
            print("------->setup")
        def test_a(self):
            print("------->test_a")
            assert 1
    if __name__ == '__main__':
              pytest.main("-s  test_abc.py")
      执行结果:
          test_abc.py 
          ------->before # 发现before会优先于测试类运行
          ------->setup
          ------->test_a
          .
    

    5.4.fixture第三个例子(默认设置为运行)

    示例:

     import pytest
     @pytest.fixture(autouse=True) # 设置为默认运行
     def before():
         print("------->before")
     class Test_ABC:
         def setup(self):
             print("------->setup")
         def test_a(self):
             print("------->test_a")
             assert 1
     if __name__ == '__main__':
         pytest.main("-s  test_abc.py")
    执行结果:
        test_abc.py 
        ------->before # 发现before自动优先于测试类运行
        ------->setup
        ------->test_a
            .
    

    5.5.fixture第四个例子(设置作用域为function)

    示例:

        import pytest
        @pytest.fixture(scope='function',autouse=True) # 作用域设置为function,自动运行
        def before():
            print("------->before")
        class Test_ABC:
            def setup(self):
                print("------->setup")
            def test_a(self):
                print("------->test_a")
                assert 1
            def test_b(self):
                print("------->test_b")
                assert 1
        if __name__ == '__main__':
            pytest.main("-s  test_abc.py")
    执行结果:
        test_abc.py
            ------->before # 运行第一次
            ------->setup
            ------->test_a
            .------->before # 运行第二次
            ------->setup
            ------->test_b
            .
    

    5.6.fixture第五个例子(设置作用域为class)

    示例:

        import pytest
        @pytest.fixture(scope='class',autouse=True) # 作用域设置为class,自动运行
        def before():
            print("------->before")
        class Test_ABC:
            def setup(self):
                print("------->setup")
            def test_a(self):
                print("------->test_a")
                assert 1
            def test_b(self):
                print("------->test_b")
                assert 1
        if __name__ == '__main__':
            pytest.main("-s  test_abc.py")
    执行结果:
        test_abc.py
        ------->before # 发现只运行一次
        ------->setup
            ------->test_a
            .
            ------->setup
            ------->test_b
            .
    

    5.7.fixture第六个例子(返回值)

    示例一:

    
        import pytest
        @pytest.fixture()
        def need_data():
            return 2 # 返回数字2
    
        class Test_ABC:
    
            def test_a(self,need_data):
                print("------->test_a")
                assert need_data != 3 # 拿到返回值做一次断言
    
        if __name__ == '__main__':
            pytest.main("-s  test_abc.py")
    执行结果:
        test_abc.py 
        ------->test_a
        .
    ``
    
    

    示例二:

    import pytest
    @pytest.fixture(params=[1, 2, 3])
    def need_data(request): # 传入参数request 系统封装参数
        return request.param # 取列表中单个值,默认的取值方式
    class Test_ABC:
    
        def test_a(self,need_data):
            print("------->test_a")
            assert need_data != 3 # 断言need_data不等于3
    
    if __name__ == '__main__':
        pytest.main("-s  test_abc.py")
    
     执行结果:
          # 可以发现结果运行了三次
          test_abc.py 
          1
          ------->test_a
          .
          2
          ------->test_a
          .
          3
          ------->test_a
          F
    

    6.Pytest高阶用法(二)

    前置条件:

    1.文件路径:

    - Test_App
    - - test_abc.py
    - - pytest.ini
    

    2.pyetst.ini配置文件内容:

    [pytest]
    命令行参数
    addopts = -s
    搜索文件名
    python_files = test_*.py
     搜索的类名
    python_classes = Test_*
     搜索的函数名
    python_functions = test_*
    

    6.1.跳过测试函数

    根据特定的条件,不执行标识的测试函数.
     方法:
         skipif(condition, reason=None)
     参数:
         condition:跳过的条件,必传参数
         reason:标注原因,必传参数
     使用方法:
         @pytest.mark.skipif(condition, reason="xxx") 
    

    示例:

    import pytest
    class Test_ABC:
        def setup_class(self):
            print("------->setup_class")
        def teardown_class(self):
            print("------->teardown_class")
        def test_a(self):
            print("------->test_a")
            assert 1
        @pytest.mark.skipif(condition=2>1,reason = "跳过该函数") # 跳过测试函数test_b
        def test_b(self):
            print("------->test_b")
                assert 0
    执行结果:
       test_abc.py 
       ------->setup_class
       ------->test_a #只执行了函数test_a
       .
       ------->teardown_class
           s # 跳过函数```
    
    
    

    6.2 标记为预期失败函数

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

    示例:

    import pytest
    class Test_ABC:
        def setup_class(self):
            print("------->setup_class")
        def teardown_class(self):
            print("------->teardown_class")
        def test_a(self):
            print("------->test_a")
            assert 1
        @pytest.mark.xfail(2 > 1, reason="标注为预期失败") # 标记为预期失败函数test_b
           def test_b(self):
               print("------->test_b")
              assert 0
       执行结果:
           test_abc.py 
           ------->setup_class
           ------->test_a
           .
           ------->test_b
           ------->teardown_class
           x  # 失败标记
    

    6.3 函数数据参数化

    方便测试函数对测试属于的获取。
     方法:
         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次
      
    
    

    单个参数示例:

    import pytest
    class Test_ABC:
        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
        执行结果:
        test_abc.py 
        ------->setup_class
        test data:a=3 # 运行第一次取值a=3
        .
        test data:a=6 # 运行第二次取值a=6
        . 
        ------->teardown_class
    

    多个参数示例:

    import pytest
    class Test_ABC:
        def setup_class(self):
            print("------->setup_class")
        def teardown_class(self):
            print("------->teardown_class")
    
    @pytest.mark.parametrize("a,b",[(1,2),(0,3)]) # 参数a,b均被赋予两个值,函数会运行两遍
    def test_a(self,a,b): # 参数必须和parametrize里面的参数一致
        print("test data:a=%d,b=%d"%(a,b))
        assert a+b == 3
        执行结果:
        test_abc.py 
        ------->setup_class
        test data:a=1,b=2 # 运行第一次取值 a=1,b=2
        .
        test data:a=0,b=3 # 运行第二次取值 a=0,b=3
        .
        ------->teardown_class
    

    函数返回值类型示例:

    import pytest
    def return_test_data():
        return [(1,2),(0,3)]
    class Test_ABC:
        def setup_class(self):
            print("------->setup_class")
        def teardown_class(self):
                print("------->teardown_class")
    
    @pytest.mark.parametrize("a,b",return_test_data()) # 使用函数返回值的形式传入参数值
    def test_a(self,a,b):
        print("test data:a=%d,b=%d"%(a,b))
        assert a+b == 3
        
        执行结果:
        test_abc.py 
        ------->setup_class
        test data:a=1,b=2 # 运行第一次取值 a=1,b=2
        .
        test data:a=0,b=3 # 运行第二次取值 a=0,b=3
        .
            ------->teardown_class
    

    6.4 修改 Python traceback 输出

    pytest --showlocals     # show local variables in tracebacks
    pytest -l               # show local variables (shortcut)
    pytest --tb=auto        # (default) 'long' tracebacks for the first and last
                            # entry, but 'short' style for the other entries
    pytest --tb=long        # exhaustive, informative traceback formatting
    pytest --tb=short       # shorter traceback format
    pytest --tb=line        # only one line per failure
    pytest --tb=native      # Python standard library formatting
    pytest --tb=no          # no traceback at all
    

    --full-trace 参数会打印更多的错误输出信息,比参数 --tb=long 还多,即使是 Ctrl+C 触发的错误,也会打印出来

    6.5 执行失败的时候跳转到 PDB

    执行用例的时候,跟参数 --pdb,这样失败的时候,每次遇到失败,会自动跳转到 PDB

    pytest --pdb              # 每次遇到失败都跳转到 PDB
    pytest -x --pdb           # 第一次遇到失败就跳转到 PDB,结束测试执行
    pytest --pdb --maxfail=3  # 只有前三次失败跳转到 PDB 
    

    6.6 设置断点

    在用例脚本中加入如下python代码,pytest会自动关闭执行输出的抓取,这里,其他test脚本不会受到影响,带断点的test上一个test正常输出

     import pdb; pdb.set_trace()
    

    6.7 获取用例执行性能数据

    获取最慢的10个用例的执行耗时

    pytest --durations=10
    

    6.8 生成 JUnitXML 格式的结果文件

    这种格式的结果文件可以被Jenkins或其他CI工具解析

    pytest --junitxml=path
    

    6.9禁用插件 

    例如,关闭 doctest 插件

    pytest -p no:doctest
    

    6.10 从Python代码中调用pytest

    pytest.main()                      # 基本用法
    pytest.main(['-x', 'mytestdir'])   # 传入配置参数
    
    
    // 指定自定义的或额外的插件
    # content of myinvoke.py
    import pytest
    class MyPlugin(object):
        def pytest_sessionfinish(self):
            print("*** test run reporting finishing")
    
    pytest.main(["-qq"], plugins=[MyPlugin()])
    

    6.11 测试脚本迁移后快速部署包含pytest的virtualenv

    例如你从Gitlab仓库里clone了项目组的刀刀同学编写的测试脚本到你自己的电脑里,你想修改些东西,并调试,咋办?可以通过下面的操作快速创建 VirtualEnv

    cd <repository>
    pip install -e .
    

    This will set up a symlink to your code in site-packages, allowing you to edit your code while
    your tests run against it as if it were installed.
    Setting up your project in development mode lets you avoid having to reinstall every time you want to run your tests,
    and is less brittle than mucking about with sys.path to point your tests at local code.
    Also consider using tox

     

    遇到的问题:

    问题:
    pytest可以输出覆盖率的html报告

    使用命令如下:

    pytest -vv --cov=./ --cov-report=html
    open htmlcov/index.html 

    有可能遇到报错:

    (venv) zhangxiaofans-MacBook-Pro:mgap-mendel joe$ pytest --cov-report=html
    usage: pytest [options] [file_or_dir] [file_or_dir] [...]
    pytest: error: unrecognized arguments: --cov-report=html
      inifile: None
      rootdir: /Users/joe/workspace/platform/mgap-mendel/mgap-mendel

    原因:
    缺少pytest cov的包

    解决方法
     

    pip install pytest-cov

     

     

     

     

     

    展开全文
  • Pytest和Allure测试框架-超详细版+实战

    万次阅读 多人点赞 2019-09-23 14:17:50
    文章目录一:pytest的介绍,安装,框架结构,执行方式1,特点2,安装3, pytest的框架结构4,执行方式二:Pytest -断言、跳过及运行1,Pytest -断言、跳过及运行2,mark中的skip(跳过)3,mark中的xfail(失败)4,使用...
  • pytest教程

    2018-06-28 14:34:58
    pytest 是一个强大的 Python 测试工具,它可以用于所有类型和级别的软件测试。 Pytest 可以被开发团队,QA 团队,独立测试小组,实践 TDD 的个人和开放源代 码项目
  • pytest-django:pytest的Django插件
  • pytest 简介

    2018-10-22 16:28:12
    python自动化测试框架pytest 3.9.1 官方使用简介,英文版
  • pytest 教程

    千次阅读 2019-05-28 08:46:05
    pytest pytest是一个非常成熟的全功能的Python测试框架,主要特点有以下几点: 简单灵活,容易上手; 支持参数化; 能够支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试、接口自动化...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 21,331
精华内容 8,532
关键字:

pytest