pytest中文文档教程(一)用例编写和前后置方法

一、入门使用

一、环境安装

pytest是python中的第三方库,使用之前需要先安装,在命令行中运行以下安装命令 :


pip insatll pytest

检查安装是否成功以及安装的版本,命令行命令如下:


pytest --version

执行上述命令,能够输出版本信息,那就说明安装成功啦。

二、用例编写

当我们通过pytest执行用例时,pytest会自动递归遍历执行路径下所有的目录,根据pytest中默认用例的识别的规则,自动收集测试用例。所有在使用pytest编写测试用例之前,我们首先需要了解一下pytest收集用例时默认的用例识别规则。

1、默认的用例识别的规则

  • 1、用例文件:所有文件名为 test_ 开头 或者 _test 开头的文件会被识别为用例文件。
  • 2:用例类,测试文件中每个Test开头的类就是一个测试用例类。
  • 3、测试用例:测试类中每个test开头的方法就是一条测试用例,测试文件中每个test开头的函数也是一条测试用例,

备注:上述默认的用例查找规则,可在pytest的配置文件进行修改(后续章节会详细介绍配置文件的使用)

另外pytest兼容unittest,以unittest的用例编写规范写的用例,pytest都能够识别出来

通过了解上述pytest中用例识别的规则,可以知道pytest中用例编写,能使用函数的形式,也能使用类的形式,那么接下来就分别给大家介绍一下这两种方式编写用例。

2、函数形式编写用例

规则:用例方法名以test开头即可


# \testcases\test_demo1.py

def test_demo():

    assert 100 == 100

使用命令 pytest 就可以执行测试函数,输出结果如下:


C:\testcases>pytest

======================test session starts ======================

platform win32 -- Python 3.7.3, pytest-5.4.2, py-1.8.0, pluggy-0.13.0

rootdir: C:\testcases

plugins:  testreport-1.1.2

collected 1 item                                                               

test_demo1.py .    [100%]

====================== 1 passed in 0.26s ======================

3、以类的形式编写用例

规则: 测试类命名以Test开头,用例方法以test开头


# test_demo2.py

class TestDome:

    def test_demo1(self):

        assert 11 == 11

    def test_demo(self):

        assert 22 == 21

命令pytest运行上述用例,结果如下:


====================== test session starts ======================

platform win32 -- Python 3.7.3, pytest-5.4.2, py-1.8.0, pluggy-0.13.0

rootdir: C:\testcases

plugins:  testreport-1.1.2

collected 2 items                                                                       

test_demo1.py .F                  [100%]

====================== FAILURES ======================

___________ TestDome.test_demo ____________

self = <test_demo1.TestDome object at 0x0445F450>

    def test_demo(self):

>      assert 22 == 21

E      assert 22 == 21

test_demo1.py:25: AssertionError

====================== short test summary info =======================

FAILED test_demo1.py::TestDome::test_demo - assert 22 == 21

====================== 1 failed, 1 passed in 0.53s ======================

上面的运行结果可以看出来,一条用例执行通过,一条执行失败

三、执行测试

在上面我们使用的是 pytest这个命令去执行测试用例。关于pytest执行测试,有两种方式,一种是命令行通过pytest这个命令执行,另外在代码中可以通过pytest.main()这个方法来执行测试。接下来就和大家分别详细的介绍一下pytest执行测试的方式和常用的参数

1、执行参数

测试用例


# 测试用例

class TestDome:

    def test_demo1(self):

        print('----测试用例执行-----------')

        assert 11 == 11

参数 -v: 显示测试的详细参数信息


C:\testcases>pytest -v

========================== test session starts ==========================

platform win32 -- Python 3.7.3, pytest-5.4.2, py-1.8.0, pluggy-0.13.0

cachedir: .pytest_cache

rootdir: C:\git_project\pytest-report-me-main\testcases

plugins: testreport-1.1.2

collected 1 item                                                                        test_demo1.py::TestDome::test_demo1 PASSED          [100%]

========================== 1 passed in 0.27s ==========================

参数 -s: 显示测试执行的输出信息


C:\testcases>pytest -s

=========================== test session starts ===========================

platform win32 -- Python 3.7.3, pytest-5.4.2, py-1.8.0, pluggy-0.13.0

rootdir: C:\testcases

plugins: testreport-1.1.2

collected 1 item         

test_demo1.py::TestDome::test_demo1 ----测试用例执行---输出1--------

----测试用例执行---输出2--------

PASSED

=========================== 1 passed in 0.28s ===========================

2、pytest.main执行的参数传递

pytest.main方法执行测试参数传递方式:

所以的参数放在列表中,每个参数就是列表中的一个元素


pytest.main(['-v','-s'])

详细的参数可以使用命令 pytest -h 查看

3、指定执行的测试目录

命令 pytest 测试目录路径


pytest testcase/

pytest会执行指定目录路径下所有的测试用例

4、指定执行的测试文件

命令 pytest 测试文件路径


pytest testcase/test_demo1.py

pytest会执行指定测试文件中下所有的测试用例

5、指定执行的测试类

命令 pytest 测试文件::测试类


pytest testcase/test_demo1.py::TestClass

pytest会执行指定测试类里面所有的测试用例

6、指定执行的测试用例

命令 pytest 测试文件::测试类::测试方法


pytest testcase/test_demo1.py::TestClass::test_method

pytest会执行指定的测试方法

二、前后置方法和fixture机制

一、xunit风格的前后置方法

1、函数用例的前后置方法

在模块中以函数形式定义用例,可以通过setup_functionteardown_function来定义函数用例的前后置方法,使用案例如下:


def setup_function(function):

    print("函数用例前置方法执行")



def teardown_function(function):

    print("函数用例后置方法执行")

def test_01():

    print('----用例方法01------')

运行结果:


C:\testcases>pytest -s

========================= test session starts =========================

platform win32 -- Python 3.7.3, pytest-5.4.2, py-1.8.0, pluggy-0.13.0

cachedir: .pytest_cache

rootdir: C:\testcases

plugins:  testreport-1.1.2

collected 1 item                                                           

test_demo.py

函数用例前置方法执行

----用例方法01------ .

函数用例后置方法执行

========================= 1 passed in 0.27s =========================

2、测试类中用例的前后置方法

  • 类级别的前后置方法

    pytest中测试类级别的前后置方法setup_class和teardown_class,分别在测试类中的用例执行之前执行,和测试类中所有用例执行完毕之后执行,具体使用如下:

    
    class TestDome:
    
        def test_01(self):
    
            print('----测试用例:test_01------')
    
    
    
        def test_02(self):
    
            print('----测试用例:test_02------')
    
    
    
        @classmethod
    
        def setup_class(cls):
    
            print("测试类前置方法---setup_class---")
    
    
    
        @classmethod
    
        def teardown_class(cls):
    
            print("测试类后置方法---teardown_class---")
    
    
  • 用例级别的前后置方法

    pytest中测试类中用例级别的的前后置方法setup_method和teardown_method,分别在测试类中的用例执行之前执行,和测试类中所有用例执行完毕之后执行,具体使用如下:

    
    class TestDome:
    
    
    
        def test_01(self):
    
            print('----测试用例:test_01------')
    
    
    
        def test_02(self):
    
            print('----测试用例:test_02------')
    
    
    
        @classmethod
    
        def setup_class(cls):
    
            print("测试类前置方法---setup_class---")
    
    
    
        @classmethod
    
        def teardown_class(cls):
    
            print("测试类后置方法---teardown_class---")
    
    
    
        def setup_method(function):
    
            print("测试用例前置方法---setup_method---")
    
    
    
        def teardown_method(function):
    
            print("测试用例后置方法---teardown_method---")
    
    

运行结果:


C:\testcases>pytest -s

==================== test session starts ====================

platform win32 -- Python 3.7.3, pytest-5.4.2, py-1.8.0, pluggy-0.13.0

rootdir: C:\testcases

plugins:  testreport-1.1.2

collected 2 items                                                                                                                                     

test_demo.py

测试类前置方法---setup_class---

测试用例前置方法---setup_method---

----测试用例:test_01------.

测试用例后置方法---teardown_method---

测试用例前置方法---setup_method---

----测试用例:test_02------.

测试用例后置方法---teardown_method---

测试类后置方法---teardown_class---

==================== 2 passed in 0.30s =======================

3、模块级别的前后置方法

pytest中还有setup_module和teardown_module这两个用来设置模块级别前后置方法的函数,定义在模块中,会在整个模块中所有的用例执行前和用例全部执行完毕之后会执行,具体使用如下:


class TestDome:

    def test_01(self):

        print('----测试用例:test_01------')

class TestDome2:

    def test_02(self):

        print('----测试用例:test_02------')





def setup_module(module):

    print("测试模块的前置方法---setup_module---")

def teardown_module(module):

    print("测试模块的前置方法---teardown_module---")

运行结果:


C:\testcases>pytest -s

====================== test session starts ======================

platform win32 -- Python 3.7.3, pytest-5.4.2, py-1.8.0, pluggy-0.13.0

rootdir: C:\testcases

plugins:testreport-1.1.2

collected 2 items                                                                       

test_demo.py 测试模块的前置方法---setup_module---

----测试用例:test_01------

.----测试用例:test_02------

.测试模块的前置方法---teardown_module---

====================== 2 passed in 0.27s ======================

二、fixture机制

前面我们介绍了pytest中xunit风格的前后置方法,接下来我们来看一下pytest中功能更加强大的fixture机制(测试夹具)的使用。

1、测试夹具的级别和定义

测试夹具需要使用pytest.fixture这个装饰器来定义,pytest中的测试夹具有如下几个级别:用例级别、测试类级别、模块级别,包级别,会话级别。接下来我们一起来看看夹具定义语法。

夹具定义可以通过参数scope指定夹具的级别,如果不指定夹具级别,scope 默认值为function(用例级别)

用例级别:scope = function

测试类级:scope = class

模块级别:scope = module

包级别: scope = package

会话级别:scope = session


@pytest.fixture(scope='指定夹具的级别')

def work():

    # 前置执行脚本

    yield

    # 后置执行脚本

测试夹具本质上是一个生成器函数,生产器函数在使用next进行迭代时,执行到yeild会返回数据,暂停执行,等待下一次进行迭代时才会继续执行,pytest夹具就是利用的生成器的机制,通过yeild在测试夹具将前后置代码分开执行。

注意点: 夹具只有在定义夹具的范围内才能使用。如果夹具是在类中定义的,则只能由该类内的测试用例使用。但是如果在模块的全局范围内定义的夹具,那么该模块中的每个测试用例,即使它是在一个类中定义的,都可以使用它。

知道了怎么定义夹具,那么接下来我们来看看如何使用夹具。

2、夹具的使用

测试夹具定义好之后,测试函数通过将它们声明为参数,来指定执行用例之前要执行的夹具。

当 pytest 开始运行测试时,它会查看该测试函数定义的形参,然后搜索与这些参数同名的测试夹具。一旦 pytest 找到它们,它就会运行这些夹具,接收它们返回的内容(如果有的话),并将这些返回内容作为参数传递给测试函数。

注意点:当我们使用夹具时,如果夹具的前置脚本执行完,有数据要传递用例,需要传递的数据写在yield后面即可,在使用夹具的用例或者方法中,可以通过定义的形参来获取yeild返回的数据(章节2.3中有使用案例介绍)

2.1、在用例中使用夹具

不管是函数形式定义的测试用例,还是测试类中方法的形式定义的用例,在使用的时候都是一样的,直接定义一个和要使用的夹具同名的形参即可。


import pytest

# 定义一个用例级别的夹具

@pytest.fixture

def my_fixture():

    print('------my_fixture---用例前置执行脚本--------')

    yield

    print('------my_fixture---用例后置执行脚本--------')

# 函数用例 指定测试夹具

def test_func__01(my_fixture):

    print("测试用例----test_func__01----")

class TestDome:

    # 函数用例 指定测试夹具

    def test_02(self, my_fixture):

        print('----测试用例:test_02------')



    # 函数用例 指定测试夹具

    def test_03(self):

        print('----测试用例:test_03------')

运行结果


C:\testcases>pytest -s

======================== test session starts ========================

platform win32 -- Python 3.7.3, pytest-5.4.2, py-1.8.0, pluggy-0.13.0

rootdir: C:\testcases

plugins: testreport-1.1.2

collected 2 items 

test_demo.py

------my_fixture---前置执行脚本--------

测试用例----test_func__01----.

------my_fixture---后置执行脚本--------

------my_fixture---前置执行脚本--------

----测试用例:test_02------.

------my_fixture---后置执行脚本--------

----测试用例:test_03------

======================== 2 passed in 0.27s ========================

上面test_func__01和test_02这两个用例在定义时指定了测试夹具,而test_03则没有指定执行的夹具,执行用例时库看到指定了夹具的用例,执行了对应的夹具。

2.2、测试类和模块指定夹具

上面我们通过给用例方法加形参来给单个测试用例指定测试夹具。如果一个测试类中有很多测试用例或者一个模块中有很多用例,都要指定同一个测试夹具,要我们则可以通过usefixtures给测试类或测试模块指定测试夹具。

给测试类中所有的用例指定夹具


# TestDome这个测试类的所有测试用例均执行my_fixture这个夹具

@pytest.mark.usefixtures('my_fixture这个夹具')

class TestDome:

    # 函数用例 指定测试夹具

    def test_02(self):

        print('----测试用例:test_01------')

    # 函数用例 指定测试夹具

    def test_03(self):

        print('----测试用例:test_02------')

使用pytestmark 在测试模块级别 指定模块所有用例执行的夹具


# test_demo.py

# 当前模块中所有的用例,均执行my_fixture这个测试夹具

pytestmark = pytest.mark.usefixtures('my_fixture')

# 函数用例 指定测试夹具

def test_func__01(my_fixture):

    print("测试用例————test_func__01——————")



class TestDome:

    # 函数用例 指定测试夹具

    def test_02(self):

        print('----测试用例:test_01------')

    # 函数用例 指定测试夹具

    def test_03(self):

        print('----测试用例:test_02------')

2.3、在夹具中引用夹具

pytest 的最大优势之一是其极其灵活的夹具系统。通过测试夹具我们可以将极为复杂化的前后置依赖,拆分为更简单单一功能的测试夹具,通过在夹具中引用其他的夹具,来组织不同用例所需的复杂依赖环境。接下来我们通过一个案例来给大家演示如何使用。


import pytest

# 用户注册的夹具

@pytest.fixture

def register_user():

    print('---用户注册的夹具前置执行----')

    # ...注册代码省略,注册的用户信息如下

    user_info = {'user': 'lemonban', 'pwd': '123456'}

    yield user_info

    print('---用户注册的夹具后置执行----')

# 用户登录的夹具,通过定义形参来使用register_user这个夹具

@pytest.fixture

def user_login(register_user):

    print('---用户登录的夹具前置执行----')

    # 获取register_user结局前置脚本执行完,yeild传递出来的数据

    user_info = register_user

    # ...登录代码省略,下面为登录得到的token

    token = 'sdjasjdask'

    yield token

    print('---用户登录的夹具后置执行----')

# 函数用例 指定使用测试夹具user_login

def test_func__01(user_login):

    token = user_login

    print("测试用例夹具user_login传递过来的token:",token)

    print("测试用例---test_func__01---")

运行结果


C:\testcases>pytest -s

======================== test session starts ========================

platform win32 -- Python 3.7.3, pytest-5.4.2, py-1.8.0, pluggy-0.13.0

rootdir: C:\testcases

plugins: testreport-1.1.2

collected 1 item 

test_demo.py

---用户注册的夹具前置执行----

夹具register_user传递过来的用户信息: {'user': 'lemonban', 'pwd': '123456'}

---用户登录的夹具前置执行----

测试用例夹具user_login传递过来的token: sdjasjdask

测试用例---test_func__01---.

---用户登录的夹具后置执行----

---用户注册的夹具后置执行----

2.4、自动使用夹具

在定义测试夹具 我们可以给夹具的装饰器加参数autouse=True来使夹具成为自动执行的夹具。具体案例如下:


import pytest

@pytest.fixture(autouse=True)

def my_fixture():

    print('------my_fixture---前置执行脚本--------')

    yield

    print('------my_fixture---后置执行脚本--------')

class TestDome:

    # 函数用例 指定测试夹具

    def test_02(self):

        print('----测试用例:test_01------')

    # 函数用例 指定测试夹具

    def test_03(self):

        print('----测试用例:test_02------')

class TestDome2:

    # 函数用例 指定测试夹具

    def test_03(self):

        print('----测试用例:test_03------')

执行结果:


C:\testcases>pytest -s

======================== test session starts ========================

platform win32 -- Python 3.7.3, pytest-5.4.2, py-1.8.0, pluggy-0.13.0

rootdir: C:\testcases

plugins: testreport-1.1.2

collected 3 items         

test_demo.py

------my_fixture---前置执行脚本--------

----测试用例:test_01------.

------my_fixture---后置执行脚本--------

------my_fixture---前置执行脚本--------

----测试用例:test_02------.

------my_fixture---后置执行脚本--------

------my_fixture---前置执行脚本--------

----测试用例:test_03------.

------my_fixture---后置执行脚本--------

======================== 3 passed in 0.29s ========================

从上面的执行结果我们可以看到,每条用例执行之前都自动执行了测试夹具my_fixture

3、conftest.py

在一个项目的测试中,大多数情况下会有多个类、模块、或者包要使用相同的测试夹具。这种情况下如果我们把测试夹具定义在某一个模块中则无法实现共享,针对这种情况,我们可以把需要共享的测试夹具放入一个单独的conftest.py文件中 ,这样多个可以实现多个测试模块共享了

ps : pytest运行测试时,如果项目中有conftest.py,那么pytest会自动加载conftest.py模块中的内容,可以把conftest看出pytest会自动加载的插件模块,后续的教程中会涉及到在conftest.py中定义pytest的hooks函数

接下来我们来看一个conftest.py定义测试夹具的案例

在 conftest.py中定义测试夹具my_fixture


# conftest.py

import pytest

@pytest.fixture

def my_fixture():

    print('------my_fixture---前置执行脚本--------')

    yield

    print('------my_fixture---后置执行脚本--------')

在test_demo1.py的用例用使用conftest.py中定义的夹具


# test_demo1.py

class TestDome:

    # 函数用例 指定测试夹具

    def test_02(self,my_fixture):

        print('----测试用例:test_01------')

    # 函数用例 指定测试夹具

    def test_03(self,my_fixture):

        print('----测试用例:test_02------')

在test_demo2.py的用例用使用conftest.py中定义的夹具


# test_demo2.py

class TestDome2:

    # 函数用例 指定测试夹具

    def test_03(self,my_fixture):

        print('----测试用例:test_03------')

执行结果:


C:\testcases>pytest -s

======================== test session starts ========================

platform win32 -- Python 3.7.3, pytest-5.4.2, py-1.8.0, pluggy-0.13.0

rootdir: C:\testcases

plugins: testreport-1.1.2

collected 3 items

test_demo.py

------my_fixture---前置执行脚本--------

----测试用例:test_01------.

------my_fixture---后置执行脚本--------

------my_fixture---前置执行脚本--------

----测试用例:test_02------.

------my_fixture---后置执行脚本--------

test_demo2.py

------my_fixture---前置执行脚本--------

----测试用例:test_03------.

------my_fixture---后置执行脚本--------

======================== 3 passed in 0.29s ========================

上述案例中我们可以发现 est_demo.py和est_demo2.py中的用例可以成功使用conftest.py中的测试用例。

©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容