• pytest fixture及conftest详解三 (pytest.ini配置文件)


    在这里插入图片描述


    一、pytest.ini介绍

    是pytest框架的主配置文件,实际生产中主要用来规范日志的格式或日志文件保存的位置,增加用例标签等等,总之简单易用,属于pytest学习的重要知识点。

    特别注意:
    pytest.ini文件命名不能修改,文件中第一行必须用【pytest】申明这是一个pytest的ini文件

    二、自定义mark标签

    我门在编写自动化测试用例时,会有各种类型的场景用例,我们又不想一次性运行全部,只想运行其中的几个,这时我们可以借助mark标签来管理测试用例,mark标签是任意取的,但是要避开Python和pytest关键字,运行标签用 - m 来运行,如:pytest -m div testcases/menus/test_menus1.py::TestMenus

    特别注意:
    多个标签要换行,且不能在顶格写,要有空格

    在这里插入图片描述

    1.案例:只执行div的测试用例

    # encoding=utf-8
    import pytest
    
    class TestMenus:
    
        @pytest.mark.div
        def test_menu1(self):
            assert 1 == 1
    
        @pytest.mark.div
        @pytest.mark.add
        def test_menu2(self):
            assert 1 == 1
    
        def test_menu3(self):
            assert 2 == 5
    
    
    if __name__ == '__main__':
        pytest.main()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    执行命令行:

    D:\project_development\api_pytest>pytest -vs -m div testcases/menus/test_menus1.py::TestMenus
    
    
    • 1
    • 2

    执行测试结果

    ======================================================= test session starts =======================================================
    platform win32 -- Python 3.9.6, pytest-5.2.1, py-1.10.0, pluggy-0.13.1
    rootdir: D:\project_development\api_pytest, inifile: pytest.ini
    plugins: allure-pytest-2.9.43, Faker-14.1.0, testreport-1.1.2
    collected 3 items / 1 deselected / 2 selected                                                                                      
    
    testcases/menus/test_menus1.py::TestMenus::test_menu1 ----这是前置方法----
    PASSED
    testcases/menus/test_menus1.py::TestMenus::test_menu2 PASSED----这是后置方法----
    
    
    
    ================================================= 2 passed, 1 deselected in 0.10s =================================================
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.注册标记来防止拼写错误

    自定义标记可以简化测试工作,让我们用指定的标记运行某个测试子集。但是,标记很容易拼错,比如把@pytest.mark.smoke拼成@pytest.mark.somke,默认情况下。这不会引起程序错误。pytest会以为这是你创建的另一个标记。为了避免拼写错误。可以在pytest.ini文件里注册标记
    标记完可以通过:pytest --markers 查看
    在这里插入图片描述

    案例1:注册标记使用正确

    [pytest]
    ;python_files = check*
    ;python_functions = check*
    ;python_classes = CHECK*
    
    markers =
        smoke: Run the smoke test functions for tasks project
        get: Run the test functions that test tasks.get()
        div
        add
    addopts= -v -s --capture=no
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    test_menus.py

    # encoding=utf-8
    import pytest
    import logging
    
    class TestMenus:
    
        @pytest.mark.smoke
        def test_menu1(self):
            logging.info('执行测试用例1')
            assert 1 == 1
    
    
        @pytest.mark.smoke
        def test_menu2(self):
            logging.info('执行测试用例2')
            assert 1 == 1
    
        def test_menu3(self):
            logging.info('执行测试用例3')
            assert 2 == 5
    
    
    if __name__ == '__main__':
        pytest.main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    执行命令:pytest -m smoke

    collected 3 items / 1 deselected / 2 selected                                                                                      
    
    testcases/menus/test_menus1.py::TestMenus::test_menu1 ----这是前置方法----
    
    ---------------------------------------------------------- live log call ----------------------------------------------------------
    2022-10-30 10:41:22 [INFO] 执行测试用例1 (test_menus1.py:9)
    PASSED
    testcases/menus/test_menus1.py::TestMenus::test_menu2
    ---------------------------------------------------------- live log call ----------------------------------------------------------
    2022-10-30 10:41:22 [INFO] 执行测试用例2 (test_menus1.py:15)
    PASSED----这是后置方法----
    
    
    ================================================= 2 passed, 1 deselected in 0.13s =================================================
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    案例2:注册标记使用错误

    执行命令:pytest -m smoke1(smoke1没有注册)
    把smoke故意写错了,也没有报错,只是给我们一个警告,只需要我们在ini里注册下就不会有警告了

    pytest -m smoke1
    
    • 1
    D:\project_development\api_pytest>pytest -m smoke1
    ======================================================= test session starts =======================================================
    platform win32 -- Python 3.9.6, pytest-5.2.1, py-1.10.0, pluggy-0.13.1 -- d:\python3.9\python.exe
    cachedir: .pytest_cache
    metadata: {'Python': '3.9.6', 'Platform': 'Windows-10-10.0.19044-SP0', 'Packages': {'pytest': '5.2.1', 'pluggy': '0.13.1'}, 'Plugins
    ': {'allure-pytest': '2.9.43', 'Faker': '14.1.0', 'html': '3.2.0', 'metadata': '2.0.3', 'testreport': '1.1.2'}, 'JAVA_HOME': 'C:\\Pr
    ogram Files\\Java\\jdk1.8.0_291'}
    rootdir: D:\project_development\api_pytest, inifile: pytest.ini
    plugins: allure-pytest-2.9.43, Faker-14.1.0, html-3.2.0, metadata-2.0.3, testreport-1.1.2
    collected 3 items / 3 deselected                                                                                                   
    
    ====================================================== 3 deselected in 0.06s ======================================================
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3.指定pytest忽略某些目录(norecurse)

    pytest执行测试搜索时,会递归遍历所有子目录,包括某些你明知道没必要遍历的目录。遇到这种情况,你可以使用norecurse选项简化pytest的搜索工作。
    在这里插入图片描述

    pytest.ini
    把menus用例目录注销了,不会去执行这个目录下的用例了

    [pytest]
    
    norecursedirs = .* venv menus *.egg dist build
    url = https://blog.csdn.net/YZL40514131
    markers =
        smoke: Run the smoke test functions for tasks project
        get: Run the test functions that test tasks.get()
        div
        add
    addopts = -v -s --capture=no
    
    log_cli = true
    log_cli_level = info
    log_cli_format = %(asctime)s [%(levelname)s] %(message)s (%(filename)s:%(lineno)s)
    log_cli_date_format = %Y-%m-%d %H:%M:%S
    log_file = ./logs/all.log
    log_file_level = info
    log_file_format = %(asctime)s [%(levelname)s] %(message)s (%(filename)s:%(lineno)s)
    log_file_date_format = %Y-%m-%d %H:%M:%S
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    执行结果

    collected 3 items                                                                                                                  
    
    testcases/works/test_work1.py::TestWork::test_h ----这是前置方法----
    
    读取到配置文件的url地址:https://blog.csdn.net/YZL40514131
    用例:https://blog.csdn.net/YZL40514131
    PASSED
    testcases/works/test_work1.py::TestWork::test_work1 PASSED
    testcases/works/test_work1.py::TestWork::test_work2 PASSED----这是后置方法----
    
    
    ======================================================== 3 passed in 0.14s ========================================================
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    也可以指定多个目录

    norecursedirs = .* venv menus works *.egg dist build
    
    • 1

    4.指定测试目录(testpaths)

    norecuredirs告诉pytest哪些路径不用访问,而testpaths则指示pytest去哪里访问。testpaths是一系列相对于根目录的路径,用于限定测试用例的搜索范围。只有在pytest未指定文件目录参数或测试用例标识符时,该选项才有作用

    pytest.ini
    如果我们只想执行testcases/menus下的测试用例,则可以把testcases/menus放到testpaths里

    [pytest]
    
    testpaths = testcases/menus
    url = https://blog.csdn.net/YZL40514131
    markers =
        smoke: Run the smoke test functions for tasks project
        get: Run the test functions that test tasks.get()
        div
        add
    addopts = -v -s --capture=no
    
    log_cli = true
    log_cli_level = info
    log_cli_format = %(asctime)s [%(levelname)s] %(message)s (%(filename)s:%(lineno)s)
    log_cli_date_format = %Y-%m-%d %H:%M:%S
    log_file = ./logs/all.log
    log_file_level = info
    log_file_format = %(asctime)s [%(levelname)s] %(message)s (%(filename)s:%(lineno)s)
    log_file_date_format = %Y-%m-%d %H:%M:%S
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    执行命令

    collected 3 items                                                                                                                  
    
    testcases/menus/test_menus1.py::TestMenus::test_menu1 ----这是前置方法----
    
    ---------------------------------------------------------- live log call ----------------------------------------------------------
    2022-10-30 11:34:00 [INFO] 执行测试用例1 (test_menus1.py:9)
    PASSED
    testcases/menus/test_menus1.py::TestMenus::test_menu2
    ---------------------------------------------------------- live log call ----------------------------------------------------------
    2022-10-30 11:34:00 [INFO] 执行测试用例2 (test_menus1.py:15)
    PASSED
    testcases/menus/test_menus1.py::TestMenus::test_menu3
    ---------------------------------------------------------- live log call ----------------------------------------------------------
    2022-10-30 11:34:00 [INFO] 执行测试用例3 (test_menus1.py:19)
    PASSED----这是后置方法----
    
    
    ======================================================== 3 passed in 0.09s ========================================================
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    5.如果我既指定了testpaths和 norecursedirs ,而且两个是一样的,结果会怎样

    在这里插入图片描述
    从上面两次的运行结果可以看出,如果既指定了testpaths和 norecursedirs ,而且两个是一样的,则是按照testpaths执行的

    collected 3 items                                                                                                                  
    
    testcases/menus/test_menus1.py::TestMenus::test_menu1 ----这是前置方法----
    
    ---------------------------------------------------------- live log call ----------------------------------------------------------
    2022-10-30 11:38:28 [INFO] 执行测试用例1 (test_menus1.py:9)
    PASSED
    testcases/menus/test_menus1.py::TestMenus::test_menu2
    ---------------------------------------------------------- live log call ----------------------------------------------------------
    2022-10-30 11:38:28 [INFO] 执行测试用例2 (test_menus1.py:15)
    PASSED
    testcases/menus/test_menus1.py::TestMenus::test_menu3
    ---------------------------------------------------------- live log call ----------------------------------------------------------
    2022-10-30 11:38:28 [INFO] 执行测试用例3 (test_menus1.py:19)
    PASSED----这是后置方法----
    
    
    ======================================================== 3 passed in 0.09s ========================================================
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    三.自定义运行时的默认参数

    pytest有多个经常使用的参数,如 - vs 来打印更详细的信息,但是每次都要手动输入很麻烦,例如上个案例 pytest -vs -m div testcases/menus/test_menus1.py::TestMenus
    这是需要用到 addopts 配置默认运行参数

    特别注意
    addopts 运行时参数(可添加多个命令行参数,空格分隔,所有参数与命令行一致)

    案例:

    pytest.ini

    [pytest]
    markers =
        smoke: Run the smoke test functions for tasks project
        get: Run the test functions that test tasks.get()
        div
        add
    addopts= -v -s
    
    url = https://blog.csdn.net/YZL40514131
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    test_menus1.py

    # encoding=utf-8
    import pytest
    
    class TestMenus:
    
        @pytest.mark.div
        def test_menu1(self):
            assert 1 == 1
    
        @pytest.mark.div
        @pytest.mark.add
        def test_menu2(self):
            assert 1 == 1
    
        def test_menu3(self):
            assert 2 == 5
    
    
    if __name__ == '__main__':
        pytest.main()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    命令行执行:pytest -m div testcases/menus/test_menus1.py::TestMenus

    pytest -m div testcases/menus/test_menus1.py::TestMenus
    
    • 1

    执行结果

    collected 3 items / 1 deselected / 2 selected                                                                                      
    
    testcases/menus/test_menus1.py::TestMenus::test_menu1 ----这是前置方法----
    PASSED
    testcases/menus/test_menus1.py::TestMenus::test_menu2 PASSED----这是后置方法----
    
    
    ================================================= 2 passed, 1 deselected in 0.10s =================================================
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    四.格式化日志

    案例

    pytest.ini

    [pytest]
    markers =
        smoke: Run the smoke test functions for tasks project
        get: Run the test functions that test tasks.get()
        div
        add
    addopts= -v -s --capture=no
    
    
    log_cli = true
    log_cli_level = info
    log_cli_format = %(asctime)s [%(levelname)s] %(message)s (%(filename)s:%(lineno)s)
    log_cli_date_format = %Y-%m-%d %H:%M:%S
    log_file = ./logs/all.log
    log_file_level = info
    log_file_format = %(asctime)s [%(levelname)s] %(message)s (%(filename)s:%(lineno)s)
    log_file_date_format = %Y-%m-%d %H:%M:%S
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    test_menus.py

    # encoding=utf-8
    import pytest
    import logging
    
    class TestMenus:
    
        @pytest.mark.div
        def test_menu1(self):
            logging.info('执行测试用例1')
            assert 1 == 1
    
        @pytest.mark.div
        @pytest.mark.add
        def test_menu2(self):
            logging.info('执行测试用例2')
            assert 1 == 1
    
        def test_menu3(self):
            logging.info('执行测试用例3')
            assert 2 == 5
    
    
    if __name__ == '__main__':
        pytest.main()
    
    
    • 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

    执行命令:pytest testcases/menus/test_menus1.py::TestMenus

    执行结果

    testcases/menus/test_menus1.py::TestMenus::test_menu1 ----这是前置方法----
    
    ---------------------------------------------------------- live log call ----------------------------------------------------------
    2022-10-29 23:37:46 [INFO] 执行测试用例1 (test_menus1.py:9)
    PASSED
    testcases/menus/test_menus1.py::TestMenus::test_menu2
    ---------------------------------------------------------- live log call ----------------------------------------------------------
    2022-10-29 23:37:46 [INFO] 执行测试用例2 (test_menus1.py:15)
    PASSED
    testcases/menus/test_menus1.py::TestMenus::test_menu3
    ---------------------------------------------------------- live log call ----------------------------------------------------------
    2022-10-29 23:37:46 [INFO] 执行测试用例3 (test_menus1.py:19)
    FAILED----这是后置方法----
    
    
    ============================================================ FAILURES =============================================================
    ______________________________________________________ TestMenus.test_menu3 _______________________________________________________
    
    self = <testcases.menus.test_menus1.TestMenus object at 0x00000173C6D7A760>
    
        def test_menu3(self):
            logging.info('执行测试用例3')
    >       assert 2 == 5
    E       assert 2 == 5
    E         -2
    E         +5
    
    testcases\menus\test_menus1.py:20: AssertionError
    -------------------------------------------------------- Captured log call --------------------------------------------------------
    INFO     root:test_menus1.py:19 执行测试用例3
    =================================================== 1 failed, 2 passed in 0.17s ===================================================
    
    • 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

    五.自定义测试文件命名规则

    测试用例默认命名规则

    除非pytest命令指定到测试用例文件,否则测试用例文件命名应该以 test_开头或者以_test结尾。
    测试函数命名,测试类的方法命名应该以test_开头。
    测试类命名应当以Test开头。
    tips: 测试类的不应该有构造函数。

    python_files 自定义测试文件命名规则
    python_classes = Test_* 自定义测试类命名规则
    python_functions= test_* check_* 自定义测试方法命名规则

    在这里插入图片描述

    pytest 框架可以通过pytest.ini配置文件自定义命名规则,在某些特定场景下可能会用到。

    特别注意:
    想控制多种文件类型,用空格隔开

    案例

    pytest.ini文件

    [pytest]
    python_files = check*
    python_functions = check*
    python_classes = CHECK*
    
    markers =
        smoke: Run the smoke test functions for tasks project
        get: Run the test functions that test tasks.get()
        div
        add
    addopts= -v -s --capture=no
    
    
    log_cli = true
    log_cli_level = info
    log_cli_format = %(asctime)s [%(levelname)s] %(message)s (%(filename)s:%(lineno)s)
    log_cli_date_format = %Y-%m-%d %H:%M:%S
    log_file = ./logs/all.log
    log_file_level = info
    log_file_format = %(asctime)s [%(levelname)s] %(message)s (%(filename)s:%(lineno)s)
    log_file_date_format = %Y-%m-%d %H:%M:%S
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    check_menus.py

    # encoding=utf-8
    import pytest
    import logging
    
    class CHECKclass:
    
        @pytest.mark.div
        def check_menu1(self):
            logging.info('执行测试用例1')
            assert 1 == 1
    
        @pytest.mark.div
        @pytest.mark.add
        def check_menu2(self):
            logging.info('执行测试用例2')
            assert 1 == 1
    
        def check_menu3(self):
            logging.info('执行测试用例3')
            assert 2 == 5
    
    
    if __name__ == '__main__':
        pytest.main()
    
    
    • 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

    执行命令行:pytest

    collected 3 items                                                                                                                  
    
    testcases/menus/check_menus.py::CHECKclass::check_menu1 ----这是前置方法----
    
    ---------------------------------------------------------- live log call ----------------------------------------------------------
    2022-10-30 00:23:49 [INFO] 执行测试用例1 (check_menus.py:9)
    PASSED
    testcases/menus/check_menus.py::CHECKclass::check_menu2
    ---------------------------------------------------------- live log call ----------------------------------------------------------
    2022-10-30 00:23:49 [INFO] 执行测试用例2 (check_menus.py:15)
    PASSED
    testcases/menus/check_menus.py::CHECKclass::check_menu3
    ---------------------------------------------------------- live log call ----------------------------------------------------------
    2022-10-30 00:23:49 [INFO] 执行测试用例3 (check_menus.py:19)
    FAILED----这是后置方法----
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 相关阅读:
    专高六第一次项目答辩学到的知识点【未完成】
    Kotlin笔记(三):扩展函数,运算符重载
    请你设计一个可以解释字符串 command 的 Goal 解析器
    中国无纺布行业市场竞争分析与发展前景预测报告
    抖音店铺列表接口h5
    从源码里的一个注释,我追溯到了12年前,有点意思。
    ORACLE Redo Log Buffer 重做日志缓冲区机制的设计
    【map的实际应用,学习map,不用=白学】3302. 表达式求值【如何得到运算符优先级?自己过一遍示例即可明白】【怎么比较运算符的优先级?map】
    如何查找和安装 WORDPRESS 插件?
    3.验证面试高频问题整理(附答案)
  • 原文地址:https://blog.csdn.net/YZL40514131/article/details/127593638