自动化测试之Pytest框架(万字详解)

打印 上一主题 下一主题

主题 791|帖子 791|积分 2373

一、媒介

   pytest 是一个功能强大且易于使用的Python测试框架,它答应开发者编写简单或复杂的函数式测试。pytest 的设计理念是让测试过程尽可能的简单和直观,同时提供丰富的插件生态系统来扩展其功能。
  

  • 介绍:

    • 易用性:pytest 不需要额外的导入语句来标记测试函数(如unittest中的test_前缀),你可以直接使用尺度的断言语句(assert)来进行测试,这使得测试代码更加简洁、可读
    • 自动发现测试:pytest 可以或许自动找到并运行测试。默认环境下,它会查找文件名以test_开头或结尾的模块,以及任何以Test开头的类(无需继承自特定的父类)。在这些模块或类中,它会实行所有以test_开头的方法或函数
    • 参数化测试:pytest 支持参数化测试,这意味着你可以用差别的输入数据多次运行同一个测试函数,而不需要为每个数据点编写单独的测试函数
    • 具体的报告和输出:当测试失败时,pytest 提供了清晰的错误信息和追踪,资助你快速定位题目地点
    • 丰富的插件生态:pytest 拥有一个活泼的社区和大量的第三方插件,可以用来加强测试的功能,例如集成覆盖率报告、与CI/CD工具对接、支持异步测试等
    • 兼容其他测试框架:pytest 可以运行unittest和nose风格的测试,所以如果你有旧的测试代码,通常可以直接使用pytest来运行它们,而不需要重写
    • 内置的fixture机制:pytest 引入了fixture的概念,这是一个非常强大的特性,用于设置前置条件(比如创建数据库连接、初始化对象等),而且可以在多个测试之间共享
    • 下令行选项:pytest 提供了许多有用的下令行选项,让你可以或许机动地控制测试举动,比如选择运行特定的测试、跳过某些测试、根据关键字筛选测试等等

二、安装

2.1 下令行安装

  1. pip install pytest
复制代码
2.2 验证安装

  1. pytest --version
复制代码
三、pytest设计测试用例留意点

3.1 定名规范



  • 文件名:文件名要以test_开头或结尾 例如:test_login.py
  • 函数名:函数名要以test_开头,这样子有助与python自动取搜索他
  • 如果使用类来构造测试,类名应以 Test 开头,而且不应继承自任何特定的基类(除非是为了使用某些特性)
3.2 断言清晰



  • 使用 Python 内置的 assert 语句来进行断言。pytest 会提供具体的失败信息,因此尽量让断言语句尽可能直接明了
3.3 fixture



  • fixture是pytest中非常重要的概念,用于设置测试环境,我们要合理的使用fixture,减少代码的重复使用,进步测试效率
3.4 参数化设置



  • 使用 @pytest.mark.parametrize 装饰器可以为同一个测试函数提供多组输入数据,从而避免编写多个类似的测试函数
3.5 测试隔离



  • 使用setup和teardowm来预备测试环境
3.6 非常处理



  • 如果你的测试预期某个操纵会抛出非常,可以使用 pytest.raises 上下文管理器来检查是否确实发生了预期的非常
3.7 跳过或者预期失败



  • 对于暂时无法通过的测试,可以使用 @pytest.mark.skip 或 @pytest.mark.xfail 标记,以便在不影响团体测试结果的环境下继续开发
3.8 mocking



  • 当测试需要依赖外部系统(如数据库、网络服务等)时,考虑使用 unittest.mock 或者第三方库如 pytest-mock 来模拟这些依赖,确保测试的快速性和稳固性
3.9 标记测试



  • 使用 @pytest.mark 可以为测试添加标签,比如 slow, network, database 等,然后可以根据这些标签选择性地运行测试
四、以案例初入pytest

4.1 第一个pytest测试

创建一个名为test_demo的文件名,其中有一个函数 一个测试
  1. def func(x):
  2.     return x + 1
  3. def test_answer():
  4.     assert func(3) == 5  # 断言
复制代码
在下令行输入pytest运行,以下是输出结果
  1. $ pytest
  2. =========================== test session starts ============================
  3. platform linux -- Python 3.x.y, pytest-8.x.y, pluggy-1.x.y
  4. rootdir: /home/sweet/project
  5. collected 1 item
  6. test_sample.py F                                                     [100%]
  7. ================================= FAILURES =================================
  8. _______________________________ test_answer ________________________________
  9.     def test_answer():
  10. >       assert func(3) == 5
  11. E       assert 4 == 5
  12. E        +  where 4 = func(3)
  13. test_sample.py:6: AssertionError
  14. ========================= short test summary info ==========================
  15. FAILED test_sample.py::test_answer - assert 4 == 5
  16. ============================ 1 failed in 0.12s =============================
复制代码
4.2 多个测试分组一个类里面

创建一个名为test_demo的文件名,创建一个类 其中有两个函数
  1. class TestClass:
  2.     def test_one(self):
  3.         x = "this"
  4.         assert "h" in x
  5.     def test_two(self):
  6.         x = "hello"
  7.         assert hasattr(x, "check") # 断言x是否具有名为check的属性或方法
复制代码
在下令行输入pytest运行,以下是输出结果
  1. $ pytest -q test_class.py
  2. .F                                                                   [100%]
  3. ================================= FAILURES =================================
  4. ____________________________ TestClass.test_two ____________________________
  5. self = <test_class.TestClass object at 0xdeadbeef0001>
  6.     def test_two(self):
  7.         x = "hello"
  8. >       assert hasattr(x, "check")
  9. E       AssertionError: assert False
  10. E        +  where False = hasattr('hello', 'check')
  11. test_class.py:8: AssertionError
  12. ========================= short test summary info ==========================
  13. FAILED test_class.py::TestClass::test_two - AssertionError: assert False
  14. 1 failed, 1 passed in 0.12s
复制代码
其中第一条是成功 第二条是失败 失败原因就是在x不具有check的属性 观察失败原因重要看断言中的中心值
4.3 将多个测试用例分组

利益:
   测试构造
仅在特定类中共享用于测试的装置
在班级层面上应用标记,并让它们隐式地应用于所有测试
  1. class TestClassDemoInstance:
  2.     value = 0
  3.     def test_one(self):
  4.         self.value = 1
  5.         assert self.value == 1
  6.     def test_two(self):
  7.         assert self.value == 1
复制代码
  1. $ pytest -k TestClassDemoInstance -q
  2. .F                                                                   [100%]
  3. ================================= FAILURES =================================
  4. ______________________ TestClassDemoInstance.test_two ______________________
  5. self = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef0002>
  6.     def test_two(self):
  7. >       assert self.value == 1
  8. E       assert 0 == 1
  9. E        +  where 0 = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef0002>.value
  10. test_class_demo.py:9: AssertionError
  11. ========================= short test summary info ==========================
  12. FAILED test_class_demo.py::TestClassDemoInstance::test_two - assert 0 == 1
  13. 1 failed, 1 passed in 0.12s
复制代码
4.4 pytest运行中下令行运行可选参数

参数功能-v增长输出的具体程度-q减少输出信息-k EXPRESSION根据表达式选择运行哪些测试,例如 -k ‘not slow’ 可以跳过标记为 slow 的测试-x遇到第一个失败就退出–html=REPORT.html生成HTML格式的测试报告,需要安装 pytest-html 插件–maxfail=NUM在达到指定数量的失败后停止测试-m MARKEXPR只运行带有指定标记的测试,例如 -m slow-n NUM 或 --numprocesses=NUM使用多个进程并行运行测试,需要安装 pytest-xdist 插件-s不捕获尺度输出和错误输出,答应直接看到 print 调用的结果–ignore=path忽略指定路径下的测试文件 五、配置文件pytest.ini

   pytest.ini 文件是 pytest 的配置文件之一,用于定义项目的全局设置和选项。通过这个文件,你可以定制化测试举动,指定插件、下令行选项以及其他配置项,而无需每次都手动在下令行中输入这些参数
  1. [pytest]
  2. # 基本配置选项
  3. addopts = -ra -q --tb=short
  4. testpaths = tests/
  5. markers =
  6.     slow: marks tests as slow (deselect with '-m "not slow"')
  7.     serial: marks tests that should run in serial
  8. python_files = test_*.py *_test.py
  9. python_classes = Test* *Tests
  10. python_functions = test_*
  11. # 插件配置
  12. plugins = myplugin, otherplugin
  13. # 环境变量
  14. env =
  15.      ENV_VAR=value1
  16.      OTHER_ENV_VAR=value2
  17. # 代码覆盖率配置(需要安装 pytest-cov)
  18. addopts += --cov=myproject --cov-report=term-missing
  19. # 并行测试配置(需要安装 pytest-xdist)
  20. addopts += -n auto
  21. # 设置默认的编码为 utf-8
  22. console_output_encoding = utf-8
  23. file_system_encoding = utf-8
  24. # 设置收集器忽略某些路径
  25. norecursedirs = .git .tox dist build
  26. # 自定义日志格式(需要安装 pytest-log-clerk 或类似插件)
  27. log_cli = True
  28. log_cli_level = INFO
  29. log_cli_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)
  30. log_cli_date_format = %Y-%m-%d %H:%M:%S
复制代码
关键配置项解释


  • addopts:添加默认的下令行选项。这可以包含任何有用的 pytest 下令行参数。例如,-ra 表示表现所有错误择要,–tb=short 设置回溯输出风格
  • testpaths:指定要搜索测试的目录,默认环境下 pytest 会递归搜索当前目录及其子目录中的所有匹配文件
  • markers:定义自定义标记的资助信息,使得其他开发者更轻易理解标记的意义
  • python_files:指定哪些文件名模式被视为测试文件
  • python_classes:指定哪些类名模式被视为测试类
  • python_functions:指定哪些函数名模式被视为测试函数
  • plugins:加载额外的插件。通常不需要显式声明,因为大多数插件会自动注册
  • norecursedirs:排除不盼望递归搜索的目录
  • log_cli 和相干日记配置:控制下令行日记输出的举动(需要适当的插件支持)
  • coverage 和并行测试配置:可以通过 addopts 添加与 pytest-cov 或 pytest-xdist 相干的选项
六、conftest文件

   conftest.py 文件是 Pytest 框架中的一个特殊文件,用于包含 fixture(固定装置)和其他配置代码。Pytest 会自动加载名为 conftest.py 的文件中定义的 fixtures 和插件,而不需要在测试模块中显式导入它们。这个文件通常用来存放那些被多个测试文件共享的配置和设置
  6.1 conftest的关键点



  • 位置:conftest.py 文件应当放置在你的测试文件地点的目录或其父目录中。Pytest 会递归地查找这些文件
  • 作用域:定义在 conftest.py 中的 fixture 可以被该文件地点目录及其子目录下的所有测试文件使用
  • 内容:可以包含 fixtures、hooks(钩子函数)和其他配置选项。它不应该包含实际的测试代码
  • 定名:文件名必须严格为 conftest.py,否则 Pytest 将不会识别它
  • 初始化代码:如果需要实行一些一次性的初始化代码(比如设置日记记载、数据库连接等),可以在 conftest.py 中定义
6.2 conftest案例

例如,在 conftest.py 中定义一个 fixture,用来作为登录模块用例的前置操纵
  1. import pytest
  2. from seleium import webdirver
  3. @pytest.fixture(scope='class')
  4. def login():
  5.         driver = webdriver.Chrome()
  6.         driver.get('http://127.0.0.1')
  7.         driver.maximzie_window()
  8.         driver.implicitly_wait(10)
  9.         yield driver
  10.         driver quit()
复制代码
七、mark属性标记

   通过使用pytest.mark资助程序,您可以轻松地在测试函数上设置元数据
  7.1 内置/自定义标记



  • usefixtures - 在测试函数或类上使用fixture
  • filterwarnings-过滤测试函数的某些告诫
  • skip-总是跳过测试函数
  • skipif - 如果满足某个条件,则跳过测试函数
  • xfail - 如果满足某个条件,则产生“预期失败”结果
  • 参数化-对同一个测试函数实行多次调用
自定义标记
自定义标记就如上述pytest.ini文件,自定义标记
  1. [pytest]
  2. markers =
  3.     slow: marks tests as slow (deselect with '-m "not slow"')
  4.     serial
复制代码
7.2 @pytest.mark.parametrize:参数化测试函数

   pytest.mark.parametrize 是 pytest 框架提供的一个装饰器,用于参数化测试函数。它答应你定义多个参数集,然后针对每个参数集运行测试函数,这样可以有用地减少代码重复,而且使得测试更加机动和易于维护
  使用 @pytest.mark.parametrize 装饰器时,你需要提供两个参数:

  • 第一个参数是一个字符串,其中包含逗号分隔的参数名列表
  • 第二个参数是一个元组列表(或者可迭代的对象),每个元组代表一组测试数据,这些数据会依次传递给测试函数的相应参数
示例
  1. import pytest
  2. def add(x, y):
  3.     return x + y
  4. @pytest.mark.parametrize("x, y, expected", [
  5.     (1, 2, 3),
  6.     (0, 5, 5),
  7.     (-1, -1, -2),
  8.     (3.2, 4.8, 8.0),
  9. ])
  10. def test_add(x, y, expected):
  11.     assert add(x, y) == expected
复制代码
在这里parametrize 装饰器定义了四组x, y, expected元组,以便teat_add依次运行得出四组结果
  1. test_example.py::test_add[1-2-3] PASSED
  2. test_example.py::test_add[0-5-5] PASSED
  3. test_example.py::test_add[-1--1--2] PASSED
  4. test_example.py::test_add[3.2-4.8-8.0] FAILED
复制代码
八、Fixture装饰器

8.1 基本概念

在 pytest 中,fixture 是一种用于设置测试环境的机制。它们可以用来实行一些前置或后置操纵(例如:预备数据、启动服务、清算状态等),而且可以在多个测试之间共享。fixture 的设计使得代码复用和测试之间的依赖关系更加清晰,同时也让测试函数本身保持简洁
8.2 Fixture方法解析

fixture方法:
  1. fixture(callable_or_scope=None, *args, scope="function", params=None, autouse=False, ids=None, name=None)
复制代码


  • scope:fixture的作用域,默以为function;
  • autouse:默认:False,需要用例手动调用该fixture;如果是True,所有作用域内的测试用例都会自动调用该fixture;
  • name:装饰器的名称,同一模块的fixture相互调用发起写差别的name
作用域(scope):


  • (scope):决定了 fixture 的生命周期
  • function (默认):每个测试函数调用一次
  • class:每个测试类调用一次
  • module:每个模块加载时调用一次
  • session:整个测试会话期间只调用一次
参数化(params):


  • 可以为 fixture 提供参数,类似于参数化测试
自动应用(autouse):


  • 如果一个测试函数需要某个 fixture,pytest 会自动调用它,无需显式地传递
依赖注入(request ):


  • 一个 fixture 可以依赖于另一个 fixture,并通过参数传递来实现这种依赖关系
8.3 Fixture的创建和使用

你可以通过装饰器 @pytest.fixture 来定义一个 fixture 函数。下面是一个简单的例子
  1. import pytest
  2. @pytest.fixture
  3. def sample_data():
  4.     # 前置操作,比如初始化数据
  5.     data = {"value": 42}
  6.     yield data
  7.     # 后置操作,比如清理资源
  8.     print("Cleanup after test")
复制代码
要使用fixture,只需要将其作为参数传递给测试函数
  1. def test_with_fixture(sample_data):
  2.     assert sample_data["value"] == 42
复制代码
在这个例子中,sample_data 是一个 fixture 函数,它会在测试 test_with_fixture 运行之前被调用,提供了一个包含特定数据的字典给测试函数。yield 关键字之后的代码是后置操纵,在测试完成后实行
8.4 调用Fixture的方式

方式一:直接作为测试函数的参数
这是最常见和推荐的方式。你只需要将 fixture 名称作为参数传递给测试函数或类的方法,pytest 就会自动为你调用该 fixture
  1. import pytest
  2. @pytest.fixture
  3. def sample_data():
  4.     print("Setting up fixture")
  5.     return {"value": 42}
  6. def test_with_fixture(sample_data):
  7.     print(f"Testing with data: {sample_data}")
  8.     assert sample_data["value"] == 42
复制代码
实行结果
  1. ============================= test session starts ==============================
  2. platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
  3. rootdir: /path/to/your/project
  4. collected 1 item
  5. test_example.py::test_with_fixture Setting up fixture
  6. Testing with data: {'value': 42}
  7. PASSED
  8. ============================== 1 passed in X.XX seconds ===============================
复制代码
对于类中的方法,也可以同样地使用
  1. class TestClass:
  2.     def test_method(self, sample_data):
  3.         assert sample_data["value"] == 42
复制代码
方式二:使用 pytest.mark.usefixtures 标记
如果你不想在每个测试函数中都列出所有的 fixtures,或者你需要为多个测试函数应用同一个 fixture,可以使用 pytest.mark.usefixtures 来标记这些测试函数或整个测试类
  1. import pytest
  2. @pytest.fixture
  3. def setup():
  4.     print("Setup fixture called")
  5.     yield
  6.     print("Teardown fixture called")
  7. @pytest.fixture
  8. def another_setup():
  9.     print("\nAnother setup fixture called")
  10.     yield
  11.     print("Teardown another setup fixture called")
  12. @pytest.mark.usefixtures("setup")
  13. def test_one():
  14.     print("Test one running")
  15. @pytest.mark.usefixtures("setup")
  16. def test_two():
  17.     print("Test two running")
复制代码
实行结果
  1. ============================= test session starts ==============================
  2. platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
  3. rootdir: /path/to/your/project
  4. collected 2 items
  5. test_example.py::test_one Setup fixture called
  6. Test one running
  7. PASSED
  8. Teardown fixture called
  9. test_example.py::test_two Setup fixture called
  10. Test two running
  11. PASSED
  12. Teardown fixture called
  13. ============================== 2 passed in X.XX seconds ===============================
复制代码
你也可以一次性为多个测试函数或整个测试类添加多个 fixtures
  1. @pytest.mark.usefixtures("setup", "another_setup")
  2. class TestClass:
  3.     def test_method(self):
  4.         pass
  5.     def test_another_method(self):
  6.         pass
复制代码
实行结果
  1. ============================= test session starts ==============================
  2. platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
  3. rootdir: /path/to/your/project
  4. collected 2 items
  5. test_example.py::TestClass::test_method
  6. Setup fixture called
  7. Another setup fixture called
  8. Test method running
  9. PASSED
  10. Teardown another setup fixture called
  11. Teardown setup fixture called
  12. test_example.py::TestClass::test_another_method
  13. Setup fixture called
  14. Another setup fixture called
  15. Test another method running
  16. PASSED
  17. Teardown another setup fixture called
  18. Teardown setup fixture called
  19. ============================== 2 passed in X.XX seconds ===============================
复制代码
方式三:自动应用 (autouse=True)
当你定义一个 fixture 时,可以通过设置 autouse=True 参数使其自动应用于所有测试函数,而不需要显式地将其作为参数传递或使用 pytest.mark.usefixtures 标记
  1. import pytest
  2. @pytest.fixture(autouse=True)
  3. def always_used_fixture():
  4.     print("This fixture is automatically applied to all tests.")
  5. def test_without_explicit_dependency():
  6.     print("Running a test without explicitly depending on the fixture.")
复制代码
实行结果
  1. ============================= test session starts ==============================
  2. platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
  3. rootdir: /path/to/your/project
  4. collected 1 item
  5. test_example.py::test_with_autouse Setting up autouse fixture
  6. Setting up sample_data fixture
  7. Testing with autouse and sample_data fixture data: {'value': 42}
  8. PASSED
  9. ============================== 1 passed in X.XX seconds ===============================
复制代码
九 、pytest跳过测试用例方法

9.1 skip – 跳过测试用例



  • 您可以标记无法在某些平台上运行或预计会失败的测试功能,以便 pytest 可以相应地处理它们并提供测试会话的择要,同时保持测试套件为绿色
  • 跳过意味着您仅盼望测试在满足某些条件时才能通过,否则 pytest 应完全跳过运行测试。常见示例是在非 Windows 平台上跳过仅限 Windows 的测试,或跳过依赖于当前不可用的外部资源(例如数据库)的测试
使用 pytest.mark.skip 装饰器
   pytest.mark.skip() 通常用于在定义测试函数时标记该函数应该被跳过,而不是在函数内部使用
如果你想在定义测试函数时提供跳过的原因,可以使用带有 reason 参数的 pytest.mark.skip 装饰器
  1. import pytest
  2. @pytest.mark.skip(reason="This test is skipped because it's not ready yet.")
  3. def test_skip_with_reason():
  4.     print("This test should be skipped and you should see the reason why.")
复制代码
使用 pytest.skip() 在函数内部跳过
   如果你需要根据某些运行时条件来决定是否跳过测试,可以在测试函数内部使用 pytest.skip() 函数
  1. import pytest
  2. def test_skip_inside_function():
  3.     condition = False  # 这里可以是任何条件判断
  4.     if not condition:
  5.         pytest.skip("Skipping this test based on a runtime condition.")
  6.     print("This part of the test will only run if the condition is True.")
复制代码
结合两种方法
   下面是一个完备的例子,展示了怎样使用 pytest.mark.skip 和 pytest.skip():
  1. import pytest
  2. # 使用装饰器跳过测试并提供原因
  3. @pytest.mark.skip(reason="This test is not implemented yet.")
  4. def test_skip_with_reason():
  5.     print("This test should be skipped.")
  6. # 根据条件在函数内部跳过测试
  7. def test_skip_inside_function():
  8.     condition = False  # 这里可以是任何条件判断
  9.     if not condition:
  10.         pytest.skip("Skipping this test based on a runtime condition.")
  11.     print("This part of the test will only run if the condition is True.")
  12. # 正常测试用例作为对比
  13. def test_normal_case():
  14.     print("Running a normal test case.")
  15.     assert True
复制代码
实行结果
  1. # 输入
  2. pytest -v -s test_example.py
  3. # 结果
  4. ============================= test session starts ==============================
  5. platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
  6. rootdir: /path/to/your/project
  7. collected 3 items
  8. test_example.py::test_skip_with_reason SKIPPED (This test is not implemented yet.)
  9. test_example.py::test_skip_inside_function
  10. Skipping this test based on a runtime condition.
  11. SKIPPED
  12. test_example.py::test_normal_case Running a normal test case.
  13. PASSED
  14. ============================== 1 passed, 2 skipped in X.XX seconds ===============================
复制代码
9.2 skipif – 有条件跳过测试用例



  • pytest.mark.skipif 是 pytest 提供的一个装饰器,用于根据给定条件跳过测试用例。如果提供的条件为 True,则该测试将被跳过;如果条件为 False,则测试会正常运行。你可以通过传递一个布尔表达式和一个可选的 reason 参数来解释为什么跳过测试
使用 pytest.mark.skipif
  1. import pytest
  2. # 如果条件为 True,则跳过测试
  3. @pytest.mark.skipif(True, reason="This test is skipped because the condition is True.")
  4. def test_skipif_with_true_condition():
  5.     print("This test should be skipped.")
  6. # 如果条件为 False,则测试不会被跳过
  7. @pytest.mark.skipif(False, reason="This test will not be skipped because the condition is False.")
  8. def test_skipif_with_false_condition():
  9.     print("This test should run.")
复制代码
依赖外部条件
通常,你会使用 skipif 来检查一些外部条件,比如环境变量、操纵系统范例或第三方库的存在等
以下是在 Python3.8 之前的解释器上运行时标记要跳过的测试函数的示例
  1. import sys
  2. import pytest
  3. # 根据 Python 版本跳过测试
  4. @pytest.mark.skipif(sys.version_info < (3, 8), reason="Requires Python 3.8 or higher")
  5. def test_requires_python_38():
  6.     print("Running a test that requires Python 3.8 or higher.")
复制代码
结合多个条件
你还可以将多个条件组合起来,或者在 fixture 中使用 skipif
  1. import pytest
  2. # 定义一个 fixture,它可以根据条件跳过所有使用它的测试
  3. @pytest.fixture
  4. def check_environment():
  5.     if some_condition:  # 替换为实际条件判断
  6.         pytest.skip("Skipping due to environment configuration.")
  7. # 使用 fixture 的测试函数
  8. def test_with_check_environment(check_environment):
  9.     print("This test runs only if the environment check passes.")
  10. # 结合多个条件
  11. @pytest.mark.skipif(
  12.     sys.platform == "win32" and sys.version_info < (3, 8),
  13.     reason="This test requires Python 3.8 or higher on Windows."
  14. )
  15. def test_combined_conditions():
  16.     print("Running a test with combined conditions.")
复制代码
输出结果
  1. ============================= test session starts ==============================
  2. platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
  3. rootdir: /path/to/your/project
  4. collected 3 items
  5. test_example.py::test_with_check_environment
  6. This test runs only if the environment check passes.
  7. PASSED
  8. test_example.py::test_combined_conditions
  9. Running a test with combined conditions.
  10. PASSED
  11. test_example.py::test_normal_case
  12. Running a normal test case.
  13. PASSED
  14. ============================== 3 passed in X.XX seconds ===============================
复制代码
十、失败重跑

10.1 使用 --last-failed 选项



  • 这个选项会只运行上一次测试会话中失败的测试用例,而跳过所有通过的测试用例。这对于快速重新运行失败的测试非常有用
案例:
首先,让我们创建 50 个测试调用,其中只有 2 个失败
  1. # content of test_50.py
  2. import pytest
  3. @pytest.mark.parametrize("i", range(50))
  4. def test_num(i):
  5.     if i in (17, 25):
  6.         pytest.fail("bad luck")
复制代码
如果您第一次运行该程序,您将看到两个失败:
  1. $ pytest -q
  2. .................F.......F........................                   [100%]
  3. ================================= FAILURES =================================
  4. _______________________________ test_num[17] _______________________________
  5. i = 17
  6.     @pytest.mark.parametrize("i", range(50))
  7.     def test_num(i):
  8.         if i in (17, 25):
  9. >           pytest.fail("bad luck")
  10. E           Failed: bad luck
  11. test_50.py:7: Failed
  12. _______________________________ test_num[25] _______________________________
  13. i = 25
  14.     @pytest.mark.parametrize("i", range(50))
  15.     def test_num(i):
  16.         if i in (17, 25):
  17. >           pytest.fail("bad luck")
  18. E           Failed: bad luck
  19. test_50.py:7: Failed
  20. ========================= short test summary info ==========================
  21. FAILED test_50.py::test_num[17] - Failed: bad luck
  22. FAILED test_50.py::test_num[25] - Failed: bad luck
  23. 2 failed, 48 passed in 0.12s
复制代码
如果你使用以下下令运行它–lf:
  1. $ pytest --lf
  2. =========================== test session starts ============================
  3. platform linux -- Python 3.x.y, pytest-8.x.y, pluggy-1.x.y
  4. rootdir: /home/sweet/project
  5. collected 2 items
  6. run-last-failure: rerun previous 2 failures
  7. test_50.py FF                                                        [100%]
  8. ================================= FAILURES =================================
  9. _______________________________ test_num[17] _______________________________
  10. i = 17
  11.     @pytest.mark.parametrize("i", range(50))
  12.     def test_num(i):
  13.         if i in (17, 25):
  14. >           pytest.fail("bad luck")
  15. E           Failed: bad luck
  16. test_50.py:7: Failed
  17. _______________________________ test_num[25] _______________________________
  18. i = 25
  19.     @pytest.mark.parametrize("i", range(50))
  20.     def test_num(i):
  21.         if i in (17, 25):
  22. >           pytest.fail("bad luck")
  23. E           Failed: bad luck
  24. test_50.py:7: Failed
  25. ========================= short test summary info ==========================
  26. FAILED test_50.py::test_num[17] - Failed: bad luck
  27. FAILED test_50.py::test_num[25] - Failed: bad luck
  28. ============================ 2 failed in 0.12s =============================
复制代码
10.2 使用 --failed-first 选项



  • 这个选项会在测试会话开始时首先运行前次失败的测试用例,然后再运行其他的测试用例。这有助于尽早发现题目,而且可以继续运行其他测试以确保没有引入新的题目
案例:
我们将编写三个测试函数:两个会成功,一个会失败。然后我们将运行这些测试,并在修复失败的测试后再次运行它们,以表现 --failed-first 的效果
  1. import pytest
  2. def test_success_one():
  3.     print("Running test_success_one")
  4.     assert True
  5. def test_success_two():
  6.     print("Running test_success_two")
  7.     assert True
  8. def test_failure():
  9.     print("Running test_failure")
  10.     assert False, "This test is supposed to fail."
复制代码
第一步:初次运行测试
首先,我们运行所有测试来确定哪些测试失败了
  1. ============================= test session starts ==============================
  2. platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
  3. rootdir: /path/to/your/project
  4. collected 3 items
  5. test_example.py::test_success_one Running test_success_one
  6. PASSED
  7. test_example.py::test_success_two Running test_success_two
  8. PASSED
  9. test_example.py::test_failure Running test_failure
  10. FAILED
  11. =================================== FAILURES ===================================
  12. _______________________________ test_failure _________________________________
  13.     def test_failure():
  14.         print("Running test_failure")
  15. >       assert False, "This test is supposed to fail."
  16. E       AssertionError: This test is supposed to fail.
  17. E       assert False
  18. test_example.py:10: AssertionError
  19. ============================== short test summary info ===============================
  20. FAILED test_example.py::test_failure - AssertionError: This test is supposed to fail.
  21. ============================== 2 passed, 1 failed in X.XX seconds ===============================
复制代码
第二步:修复失败的测试
如今我们修复 test_failure 函数中的错误:
  1. def test_failure():
  2.     print("Running test_failure (fixed)")
  3.     assert True, "This test has been fixed."
复制代码
第三步:使用 --failed-first 重新运行测试
接下来,我们使用 --failed-first 选项来确保前次失败的测试优先运行。这有助于尽早发现题目是否已经被办理
  1. ============================= test session starts ==============================
  2. platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
  3. rootdir: /path/to/your/project
  4. collected 3 items
  5. test_example.py::test_failure Running test_failure (fixed)
  6. PASSED
  7. test_example.py::test_success_one Running test_success_one
  8. PASSED
  9. test_example.py::test_success_two Running test_success_two
  10. PASSED
  11. ============================== 3 passed in X.XX seconds ===============================
复制代码
10.3 使用 pytest-rerunfailures 插件



  • 如果你需要在同一个测试会话中多次重试失败的测试,可以安装并使用 pytest-rerunfailures 插件。这个插件答应你指定一个次数,当测试失败时它会自动重试指定的次数
安装插件
  1. pip install pytest
  2. -rerunfailures
复制代码
安装条件
  1. pytest(>=5.3) and python>=3.6
复制代码
检察安装版本
  1. pip show pytest-rerunfailures
复制代码
pytest-rerunfailures方法使用


  • 下令行参数:-reruns n(重新运行次数) - rerruns -delay m (等待运行次数)
使用装饰器
@pytest.mark.flaky(reruns=5,reruns_delay=2)
下令行案例:
我们将编写三个测试函数:两个会成功,一个会失败。然后我们将运行这些测试,并在修复失败的测试后再次运行它们,以表现 pytest-rerunfailures 怎样工作
  1. import pytest
  2. def test_success_one():
  3.     print("Running test_success_one")
  4.     assert True
  5. def test_success_two():
  6.     print("Running test_success_two")
  7.     assert True
  8. def test_failure():
  9.     print("Running test_failure")
  10.     # 这个断言会在第一次执行时失败,但在后续重试中通过
  11.     if not hasattr(test_failure, "retry_count"):
  12.         test_failure.retry_count = 0
  13.     test_failure.retry_count += 1
  14.     if test_failure.retry_count < 3:
  15.         assert False, f"This test is supposed to fail on retry {test_failure.retry_count}"
  16.     else:
  17.         print("This test has been fixed and now passes.")
  18.         assert True
复制代码
第一步:初次运行测试
首先,我们运行所有测试来确定哪些测试失败了,并检察重试机制是否按预期工作
实行下令
  1. pytest --reruns 3 --reruns-delay 1 -v -s test_example.py
复制代码
这里,–reruns 3 表示每个失败的测试最多重试 3 次,–reruns-delay 1 表示每次重试之间等待 1 秒
预期结果
  1. ============================= test session starts ==============================
  2. platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
  3. rootdir: /path/to/your/project
  4. collected 3 items
  5. test_example.py::test_success_one Running test_success_one
  6. PASSED
  7. test_example.py::test_success_two Running test_success_two
  8. PASSED
  9. test_example.py::test_failure Running test_failure
  10. FAILED
  11. ---------------------------------- Captured stdout call ----------------------------------
  12. Running test_failure
  13. =================================== FAILURES ===================================
  14. _______________________________ test_failure _________________________________
  15.     def test_failure():
  16.         print("Running test_failure")
  17.         if not hasattr(test_failure, "retry_count"):
  18.             test_failure.retry_count = 0
  19.         test_failure.retry_count += 1
  20.         if test_failure.retry_count < 3:
  21. >           assert False, f"This test is supposed to fail on retry {test_failure.retry_count}"
  22. E           AssertionError: This test is supposed to fail on retry 1
  23. E           assert False
  24. test_example.py:16: AssertionError
  25. ----------------------------- RERUN test_failure ------------------------------
  26. test_example.py::test_failure (re-run 1) Running test_failure
  27. FAILED
  28. ---------------------------------- Captured stdout call ----------------------------------
  29. Running test_failure
  30. =================================== FAILURES ===================================
  31. _______________________________ test_failure _________________________________
  32.     def test_failure():
  33.         print("Running test_failure")
  34.         if not hasattr(test_failure, "retry_count"):
  35.             test_failure.retry_count = 0
  36.         test_failure.retry_count += 1
  37.         if test_failure.retry_count < 3:
  38. >           assert False, f"This test is supposed to fail on retry {test_failure.retry_count}"
  39. E           AssertionError: This test is supposed to fail on retry 2
  40. E           assert False
  41. test_example.py:16: AssertionError
  42. ----------------------------- RERUN test_failure ------------------------------
  43. test_example.py::test_failure (re-run 2) Running test_failure
  44. PASSED
  45. ---------------------------------- Captured stdout call ----------------------------------
  46. Running test_failure
  47. This test has been fixed and now passes.
  48. ============================== short test summary info ===============================
  49. FAILED test_example.py::test_failure - AssertionError: This test is supposed to fail on retry 1
  50. FAILED test_example.py::test_failure (re-run 1) - AssertionError: This test is supposed to fail on retry 2
  51. PASSED test_example.py::test_failure (re-run 2)
  52. ============================== 2 passed, 1 failed in X.XX seconds ===============================
复制代码
在这个输出中,我们可以看到 test_failure 在前两次重试中失败了,但在第三次重试中通过了。
总结


  • 初次运行:展示了哪些测试通过了,哪些失败了,而且展示了重试机制
  • 重试机制:test_failure 测试在前两次重试中失败,但在第三次重试中通过了
  • 使用 pytest-rerunfailures 插件:确保失败的测试可以在同一个测试会话中多次重试,从而减少由于环境或其他不稳固因素导致的假阳性失败
十一、pytest实行次序

   在 pytest 中,测试函数的实行次序默认是按照它们在文件中的定义次序。然而,有时候你可能盼望控制测试的实行次序,例如确保某些依赖关系得以满足或优化测试运行时间。pytest 提供了多种方式来控制测试实行次序,包罗使用 @pytest.mark.order 装饰器(需要安装 pytest-ordering 插件)和内置的 pytest-order 插件
  安装插件
pip install pytest
-order
案例:
我们将创建几个测试函数,并使用 @pytest.mark.order 来指定它们的实行次序
  1. import pytest
  2. @pytest.mark.order(2)
  3. def test_second():
  4.     print("Running second test")
  5.     assert True
  6. @pytest.mark.order(1)
  7. def test_first():
  8.     print("Running first test")
  9.     assert True
  10. @pytest.mark.order(3)
  11. def test_third():
  12.     print("Running third test")
  13.     assert True
  14. def test_unordered():
  15.     print("Running unordered test")
  16.     assert True
复制代码
在这个例子中,我们指定了三个测试的实行次序:test_first 会最先运行,然后是 test_second,最后是 test_third。test_unordered 没有指定次序,因此它将根据其在文件中的位置决定实行次序,通常是在所有有序测试之后实行
预期结果
  1. ============================= test session starts ==============================
  2. platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
  3. rootdir: /path/to/your/project
  4. collected 4 items
  5. test_example.py::test_first Running first test
  6. PASSED
  7. test_example.py::test_second Running second test
  8. PASSED
  9. test_example.py::test_third Running third test
  10. PASSED
  11. test_example.py::test_unordered Running unordered test
  12. PASSED
  13. ============================== 4 passed in X.XX seconds ===============================
复制代码
在这个输出中,可以看到测试按照我们指定的次序实行:test_first -> test_second -> test_third,而 test_unordered 在最后实行
差别的排序策略


  • 除了使用数字来指定次序外,pytest-order 还支持其他排序策略,比如按字母次序、反向次序等。你还可以结合多个装饰器来实现更复杂的排序逻辑。
示例:按字母次序实行


  • 如果你想要按字母次序实行测试,可以使用 @pytest.mark.order(“alphabetical”):
  1. @pytest.mark.order("alphabetical")
  2. def test_a():
  3.     print("Running test_a")
  4.     assert True
  5. @pytest.mark.order("alphabetical")
  6. def test_b():
  7.     print("Running test_b")
  8.     assert True
复制代码
十二、hooks(钩子函数)

12.1 钩子函数的四个阶段

12.1.1 配置阶段 (Configuration)

描述:


  • 在这个阶段,pytest 解析下令行参数、读取配置文件,并进行须要的初始化工作。你可以通过这个阶段的钩子函数来添加自定义选项或修改全局配置
常用钩子函数:


  • pytest_addoption(parser):

    • 用途:向下令行接口添加自定义选项
    • 示例:

  1. def pytest_addoption(parser):
  2.     parser.addoption("--runslow", action="store_true", help="run slow tests")
复制代码


  • pytest_configure(config):

    • 用途:在所有测试开始前进行全局配置,比如注册 markers 或设置其他全局状态。
    • 示例:

  1. def pytest_configure(config):
  2.     config.addinivalue_line("markers", "slow: mark test as slow to run")
复制代码
12.2 收集阶段 (Collection)

描述:


  • pytest 在此阶段会搜索并收集所有符合尺度的测试项(test items)。你可以在这一阶段修改哪些测试会被收集,或者改变它们的属性。
常用钩子函数:


  • pytest_collect_file(path, parent):

    • 用途:自定义文件收集器,答应 pytest 收集非尺度测试文件
    • 示例:

  1. def pytest_collect_file(parent, path):
  2.     if path.ext == ".yaml" and path.basename.startswith("test_"):
  3.         return YamlFile.from_parent(parent, fspath=path)
复制代码


  • pytest_collection_modifyitems(session, config, items):

    • 用途:修改收集到的测试项列表,例如根据条件过滤或重新排序测试项。
    • 示例:

  1. def pytest_collection_modifyitems(items):
  2.     items.sort(key=lambda item: item.name)  # 按名称排序
复制代码
12.3 运行阶段 (Running)

描述:


  • 这是实际实行测试的阶段。pytest 会依次调用每个测试项的 setup、call 和 teardown 方法。你可以在这些方法中插入额外的逻辑,如日记记载、性能监控等
常用钩子函数:


  • pytest_runtest_protocol(item, nextitem):

    • 用途:控制整个测试协议,包罗 setup、call 和 teardown。

  • pytest_runtest_setup(item):

    • 用途:在每个测试项实行之前调用,用于设置测试环境。
    • 示例:

  1. def pytest_runtest_setup(item):
  2.     print(f"Setting up {item.name}")
复制代码


  • pytest_runtest_call(item):

    • 用途:在每个测试项的实际实行过程中调用。
    • 示例:

  1. def pytest_runtest_call(item):
  2.     print(f"Calling {item.name}")
复制代码


  • pytest_runtest_teardown(item, nextitem):

    • 用途:在每个测试项实行之后调用,用于清算测试环境。
    • 示例:

  1. def pytest_runtest_teardown(item, nextitem):
  2.     print(f"Tearing down {item.name}")
复制代码


  • pytest_report_teststatus(report, config):

    • 用途:自定义测试状态报告,改变测试通过、失败或跳过的表现方式。
    • 示例:

  1. def pytest_report_teststatus(report, config):
  2.     if report.when == 'call' and report.failed:
  3.         return "failed", "F", "FAILED"
复制代码
12.4 总结阶段 (Summary)

描述:


  • 在所有测试完成后,pytest 会生成一个总结报告,表现测试结果。你可以在此阶段添加自定义的总结信息,或者修改默认的输出格式。
常用钩子函数:


  • pytest_terminal_summary(terminalreporter, exitstatus, config):

    • 用途:在终端输出总结信息。
    • 示例:

  1. def pytest_terminal_summary(terminalreporter, exitstatus, config):
  2.     print("Custom summary information")
复制代码


  • 四个阶段的关系

    • 配置阶段:为测试会话预备环境,确保统统就绪
    • 收集阶段:确定哪些测试需要运行,并构建测试项列表
    • 运行阶段:依次实行测试项,并处理每个测试的 setup、call 和 teardown
    • 总结阶段:提供测试结果的汇总信息,并结束测试会话

12.2 钩子函数关键点

1. 调用次序:相识各个阶段的钩子函数调用次序,以便在适当的时间点插入逻辑

2. 常见钩子函数:熟悉关键的钩子函数及其用途,以实现所需的定制化功能

3. request 对象:使用 request 对象提供的上下文信息来加强机动性
许多钩子函数吸收一个 request 对象作为参数,该对象提供了访问当前测试上下文的能力。request 对象非常强大,因为它包含了关于测试会话、节点、配置等方面的信息


  • request.config: 访问全局配置
  • request.node: 获取当前测试项的信息
  • request.addfinalizer(): 注册一个函数,在测试结束时调用

4. 插件兼容性:确保自定义插件与现有插件精良协作

5.文档和社区支持:充分使用官方文档和社区资源来办理题目和学习最佳实践

结合案例


  • 假设你想确保一些测试总是最先运行,而另一些则在最后运行。你可以结合 pytest_collection_modifyitems 和 @pytest.mark.order 来实现这一点
  1. import pytest
  2. def pytest_collection_modifyitems(items):
  3.     # 定义一个排序键,确保带有 'order' 标记的测试按照指定顺序执行
  4.     items.sort(key=lambda item: (getattr(item.get_closest_marker('order'), 'args', [0])[0], item.name))
  5. @pytest.mark.order(1)
  6. def test_first():
  7.     print("Running first test")
  8.     assert True
  9. @pytest.mark.order(2)
  10. def test_second():
  11.     print("Running second test")
  12.     assert True
  13. def test_unordered():
  14.     print("Running unordered test")
  15.     assert True
复制代码
在这个例子中,pytest_collection_modifyitems 确保了标记为 @pytest.mark.order 的测试按照指定次序实行,而未标记的测试则排在其后
十三、Allure测试报告

13.1 媒介

Allure 是一个机动且功能强大的测试报告工具,支持多种编程语言和测试框架,包罗 Python 的 pytest。它可以或许生成具体且雅观的测试报告,资助团队更好地理解和分析测试结果。以下是关于怎样在 pytest 中集成 Allure 测试报告的关键点和步调
13.2 安装 Allure

首先,你需要安装 Allure 和相干插件:


  • 安装 Allure 下令行工具:

    • 使用 Homebrew(MacOS):brew install allure
    • 使用 Chocolatey(Windows):choco install allure
    • 或者从 下载并手动安装。

  • 安装 pytest-allure-adaptor 插件:

    • 使用 pip 安装:pip install pytest
      -allure-adaptor

13.3 配置 pytest 以使用 Allure

1. 在下令行中启用 Allure
你可以直接在下令行中通过添加 --alluredir 参数来指定保存 Allure 结果的目录:
  1. pytest --alluredir=/path/to/result/dir
复制代码
2. 使用 pytest.ini 或 tox.ini 配置文件
你也可以将 Allure 配置添加到 pytest.ini 或 tox.ini 文件中,以便每次运行测试时自动应用:
  1. [pytest]
  2. addopts = --alluredir=allure-results
复制代码
13.4 Allure装饰器函数

装饰器函数
方法参数参数分析@allure.epic()epic描述定义项目、当有多个项目是使用。往下是feature@allure.feature()模块名称用例按照模块区分,有多个模块时给每个起名字@allure.story()用例名称一个用例的描述@allure.title(用例的标题)用例标题一个用例的标题@allure.testcase()测试用例连接的地址自动化用例对应的功能用例存放系统的地址@allure.issue()缺陷地址对应缺陷管理系统里边的缺陷地址@allure.description()用例描述对应测试用例的描述@allure.step()测试步调测试用例的操纵步调@allure.severity()用例品级blocker 、critical 、normal 、minor 、trivial@allure.link()定义连接用于定义一个需要在测试报告中展示的连接@allure.attachment()附件添加测试报告附件 13.5 实行自动化用例 生成allure报告所需文件

测试代码
  1. import pytest
  2. def test_success():
  3.     """this test succeeds"""
  4.     assert True
  5. def test_failure():
  6.     """this test fails"""
  7.     assert False
  8. def test_skip():
  9.     """this test is skipped"""
  10.     pytest.skip('for a reason!')
  11. def test_broken():
  12.     raise Exception('oops')
复制代码
运行
  1. pytest --alluredir=./results
复制代码

13.6 检察测试报告的两种方式

13.6.1 直接打开默认浏览器展示报告

  1. allure serve ./result/
复制代码

13.6.2 从结果生成报告



  • 生成报告

    • allure generate ./result/ -o ./report/ --clean (覆盖路径加–clean)

  • 打开报告

    • allure open -h 127.0.0.1 -p 8883 ./report/

十四、pytest中管理日记

14.1 日记级别

debug:打印全部日记,具体信息
info:打印info、warning、error、critical级别的日记,确认统统按预期运行
warning:打印warning、error、critical级别的日记
error:打印error、critical级别日记,或者一些更为严重,软件没能实行一些功能
critical:打印critical日记,一个严重的错误,表明程序可能无法正常的实行
品级次序:
debug–》info–》warning–》error–》critical
14.2 使用logging模块

你可以直接在测试代码中使用 logging 模块来记载信息。pytest 会自动捕获这些日记并根据上述配置进行处理
  1. import logging
  2. def test_example():
  3.     logger = logging.getLogger(__name__)
  4.     logger.info("This is an info message")
  5.     logger.debug("This is a debug message")
  6.     assert True
复制代码
14.3 将日记保存到文件

有时你可能盼望将日记保存到文件而不是仅限于终端输出。你可以通过配置 logging 模块来实现这一点
  1. import logging
  2. # 配置日志记录器以写入文件
  3. logging.basicConfig(filename='test.log', filemode='w', level=logging.INFO)
  4. def test_logging_to_file():
  5.     logger = logging.getLogger(__name__)
  6.     logger.info("Logging to file")
  7.     assert True
复制代码
此外,你也可以在 pytest.ini 中配置日记输出到文件:
  1. [pytest]
  2. log_file = test.log
  3. log_file_level = INFO
复制代码
14.4 控制日记捕获的举动

有时候你可能不想捕获某些特定的日记输出,或者想完全禁用日记捕获。你可以通过 caplog fixture 来控制日记捕获的举动
  1. def test_control_log_capture(caplog):
  2.     caplog.set_level(logging.WARNING)  # 只捕获 WARNING 级别及以上的日志
  3.     logging.info("This will not be captured")
  4.     logging.warning("This will be captured")
  5.     assert "captured" in caplog.text
复制代码
14.5 示例

  1. import logging
  2. import os
  3. import time
  4. from config.conf import BASE_DIR
  5. import colorlog
  6. log_color_config = {
  7.         'DEBUG': 'cyan',
  8.         'INFO': 'green',
  9.         'WARNING': 'yellow',
  10.         'ERROR': 'red',
  11.         'CRITICAL': 'bold_red'}
  12. log = logging.getLogger('log_name')
  13. consloe_handler = logging.StreamHandler()
  14. daytime = time.strftime("%Y-%m-%d")
  15. path = BASE_DIR + 'log/'if not os.path.exists(path):
  16.     os.makedirs(path)
  17. filename = path + f'/run_log_{daytime}.log'file_handle = logging.FileHandler(filename=filename, mode='a', encoding="utf-8")
  18. log.setLevel(logging.DEBUG)
  19. consloe_handler.setLevel(logging.DEBUG)
  20. file_handle.setLevel(logging.INFO)
  21. file_formatter = logging.Formatter(
  22.     fmt='%(asctime)s - %(levelname)s - %(name)s - %(module)s:%(funcName)s:%(lineno)d - %(message)s',
  23.     datefmt='%Y-%m-%d %H:%M:%S')
  24. console_formatter = colorlog.ColoredFormatter(
  25.     fmt='%(log_color)s%(levelname)-8s%(reset)s | %(log_color)s%(message)s%(reset)s | %(white)s%(asctime)s | %(blue)s%(name)s:%(filename)s:%(lineno)d%(reset)s',
  26.     datefmt='%Y-%m-%d %H:%M:%S',  # 设置日期/时间格式    reset=True,  # 自动重置颜色到默认值    log_colors=log_color_config,  # 使用上面定义的日志等级颜色配置    secondary_log_colors={},  # 可选:为特定字段添加颜色    style='%'  # 使)
  27. consloe_handler.setFormatter(console_formatter)
  28. file_handle.setFormatter(file_formatter)
  29. if not log.handlers:
  30.     log.addHandler(consloe_handler)
  31.     log.addHandler(file_handle)
  32. consloe_handler.close()
  33. file_handle.close()
  34. if __name__ == '__main__':
  35.     log.debug("debug")
  36.     log.info("info")
  37.     log.warning("warning")
  38.     log.critical("critical")
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

前进之路

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表