Back to Blogs
python-pytest

Python测试框架之Pytest

Soloman
2019-04-17

Python测试框架之Pytest

Pytest 是 Python 中一个功能强大、灵活、易于上手的单元测试框架。它支持简单的函数式测试,也支持复杂的功能性测试和插件扩展,广泛用于个人项目、开源项目乃至大型企业项目中。以下是对 pytest 的详细介绍。

pip install -U pytest

1 基本规则

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

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

一般采用命令行模式运行测试文件

# pytest 文件路径/测试文件名
pytest test_module.py::TestClass::test_method
pytest -s test_soloman.py::TestSolomanClass::test_soloman_method

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

2 @pytest.fixture

fixture修饰器来标记固定的工厂函数,在其他函数,模块,类或整个工程调用它时会被激活并优先执行,通常会被用于完成预置处理和重复操作。在@pytest.fixture函数中实现初始化操作,那么用例执行完之后如需要清除数据(或还原)操作,可以使用 yield 来实现。

# test_abc.py
class Test_ABC:
    # 使用 yield 来实现创建obj,使用之后再将其删除掉
    @pytest.fixture(scope="function")
    def before(self):
        print("------->before")
        obj = Soloman(name = "Soloman", website = "www.soloman.vip")
        obj.save()
        yield obj
        obj.delete()
    # test_a方法传入了被fixture标识的函数,以变量的形式
    def test_a(self, before): 
        print("------->test_a")
        assert 1
# 调用pytest的main函数执行测试,一般用命令行:pytest -s test_abc.py
if __name__ == '__main__':
    pytest.main("-s  test_abc.py")

@pytest.fixture 作用范围

def fixture(scope="function", params=None, autouse=False, ids=None, name=None):
    """
    :arg scope:    可选四组参数:function(默认)、calss、module、package/session
    :arg params:   一个可选的参数列表,它将导致多个参数调用fixture函数和所有测试使用它。
    :arg autouse:  如果为True,则fixture func将为所有测试激活可以看到它。如果为False(默认值),则需要显式激活fixture。
    :arg ids:      每个参数对应的字符串id列表,因此它们是测试id的一部分。如果没有提供id,它们将从参数中自动生成。
    :arg name:     fixture的名称。 这默认为被装饰函数的名称。
  """

说下 scope 四组参数的意义:

  • function:每个方法(函数)都会执行一次。

  • class:每个类都会执行一次。类中有多个方法调用,只在第一个方法调用时执行。

  • module:一个 .py 文件执行一次。一个.py 文件可能包含多个类和方法。

  • package/session:多个文件调用一次,可以跨 .py 文件。

3 Pytest的setup和teardown函数

  1. setup,在测试函数或类之前执行,完成准备工作,例如数据库链接、测试数据、打开文件等
  2. teardown,在测试函数或类之后执行,完成收尾工作,例如断开数据库链接、回收内存资源等
  3. setup和teardown主要分为:模块级,类级,功能级,函数级。
  4. 备注:也可以通过上面提及的yield,在fixture函数中通过yield实现setup和teardown功能

3.1 函数级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")
# 函数级setup和teardown,运行于测试方法的始末,即:运行一次测试函数会运行一次setup和teardown
# 运行结果:setup_method test_a teardown_method setup_method test_b teardown_method

3.2 类级setup和teardown

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")
# 类级setup和teardown,运行于测试类的始末,即:在一个测试类只运行一次setup_class和teardown_class,不关心测试类内有多少个测试函数。
# 运行结果:setup_class test_a test_b teardown_class

4 conftest.py 配置文件

若有多个.py 文件需要调用某个被@pytest.fixture装饰的方法,可以把该方法方法写在 conftest.py 配置文件中。test_xxx.py 测试文件中调用时无需 import conftest,pytest 会自动搜索同级目录中的 conftest.py 文件

5 通过pytest.mark对test方法分类执行

# 通过@pytest.mark控制需要执行哪些feature的test,例如在执行test前增加修饰@pytest.mark.website。通过 -m "website" 执行有website标记的测试用例
pytest -m website test_soloman.py

# 执行没有website标记的test测试用例
pytest -m not website test_soloman.py

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

6 参考文档