pytest 框架

pytest 特点

点击这里,边看视频讲解,边学习以下内容

基于 Python 语言的自动化测试框架 最知名的 有如下 3 款

前两款框架主要(或者说很大程度上)是 聚焦 在 白盒单元测试

而 robotframework 主要聚焦在 系统测试。


pytest 可以用来做 系统测试 的自动化, 它的特点有


pytest 的功能非常 多, 我们这里主要介绍 常用的功能。

安装

直接执行 如下命令即可安装 pytest

pip install pytest 

我们还需要产生测试报表,所以要安装一个第三方插件 pytest-html ,执行如下命令安装

pip install pytest-html

快速上手

pytest 如何知道你哪些代码是自动化的测试用例?

官方文档 给出了 pytest 寻找 测试项 的 具体规则


这些规则,咋一看有点晕。 我们用例子来演示。

测试用例代码

首先,我们编写的测试用例代码文件, 必须以 test_ 开头,或者以 _test 结尾

比如,我们创建一个 文件名为 test_错误登录.py ,放在目录 autotest\cases\登录 下面。

其中 autotest 是 我们创建的 自动化项目根目录

内容如下

class Test_错误密码:

    def test_C001001(self):
        print('\n用例C001001')
        assert 1 == 1
        
    def test_C001002(self):
        print('\n用例C001002')
        assert 2 == 2
        
    def test_C001003(self):
        print('\n用例C001003')
        assert 3 == 2

如果我们把测试用例存放在类中, 类名必须以 Test 为前缀的 ,用例对应的方法必须以 test 为前缀的方法。


pytest 中用例的检查点 直接用 Python 的 assert 断言。

assert 后面的表达式结果 为 True ,就是 检查点 通过,结果为False ,就是检查点 不通过。

我们这里先快速给大家介绍 pytest 的基本用法, 就先用简单的 表达式演示一下, 后面的教程会有实际的测试代码 和 检查点。

运行测试

执行测试非常简单,打开命令行窗口,进入自动化项目根目录(我们这里就是 autotest),执行命令程序 pytest 即可

上面的示例执行结果如下

显示找到3个测试项,2个执行通过,1个不通过。

通过的用例 是用一个绿色小点表示, 不通过的用例用一个红色的F表示

并且会在后面显示具体不通过的用例 和不通过的检查点 代码细节。

直接执行 pytest 命令不会将当前目录设置为模块搜索路径

所以更推荐 执行命令 python -m pytest


大家可以发现,用例代码中有些打印语句没有显示出内容。

因为pytest 会 截获print打印的内容。

如果我们希望 显示测试代码中print的内容,因为这些打印语句在调试代码时很有用,可以加上命令行参数 -s

如下

python -m pytest -s

如果我们希望得到更详细的执行信息,包括每个测试类、测试函数的名字,可以加上参数 -v,这个参数可以和 -s 合并为 -sv

如下

python -m pytest -sv

执行 pytest 时, 如果命令行没有指定目标目录 或者 文件, 它会自动搜索当前目录下所有符合条件的文件、类、函数。

所以上面,就找到了3个测试方法,对应3个用例。

我们目前 项目根目录 中 只有一个cases 目录用例存放测试用例, 将来还会有其他目录,比如:

lib目录存放库代码、cfg目录存放配置数据 等等。

为了防止 pytest 到其他目录中找测试用例项,执行测试时,我们可以在命令行加上目标目录 cases ,就是这样

python -m pytest cases

产生报告

前面在安装pytest,我们也安装了 pytest-html 插件,这个插件就是用来产生测试报告的。

要产生报告,在命令行加上 参数 --html=report.html --self-contained-html ,如下

python -m pytest cases --html=report.html --self-contained-html

这样就会产生名为 report.html 的测试报告文件,可以在浏览器中打开


视频中讲述这个工具原来有个bug,导致测试目录、文件、类名 中,如果有中文,显示为乱码

但是最新版本问题已经解决。


您需要高效学习,找工作? 点击这里 白月黑羽实战班


初始化清除

点击这里,边看视频讲解,边学习以下内容

对自动化测试框架来说,初始化清除功能 至关重要。

模块级别

模块级别 的初始化、清除 分别 在整个模块的测试用例 执行前后执行,并且 只会执行1次

如下定义 setup_module 和 teardown_module 全局函数

def setup_module():
    print('\n *** 初始化-模块 ***')


def teardown_module():
    print('\n ***   清除-模块 ***')

class Test_错误密码:

    def test_C001001(self):
        print('\n用例C001001')
        assert 1 == 1
        
    def test_C001002(self):
        print('\n用例C001002')
        assert 2 == 2
        
    def test_C001003(self):
        print('\n用例C001003')
        assert 3 == 2


class Test_错误密码2:

    def test_C001021(self):
        print('\n用例C001021')
        assert 1 == 1
        
    def test_C001022(self):
        print('\n用例C001022')
        assert 2 == 2

执行命令 python -m pytest cases -s ,运行结果如下

collected 5 items

cases\登录\test_错误登录.py
 *** 初始化-模块 ***

用例C001001
.
用例C001002
.
用例C001003
F
用例C001021
.
用例C001022
.
 ***   清除-模块 ***

可以发现,模块级别的初始化、清除 在 整个模块所有用例 执行前后 分别 执行1次

它主要是用来为该 模块 中 所有的测试用例做 公共的 初始化 和 清除

类级别

类级别 的初始化、清除 分别 在整个类的测试用例 执行前后执行,并且 只会执行1次

如下定义 setup_class 和 teardown_class 类方法

def setup_module():
    print('\n *** 初始化-模块 ***')

def teardown_module():
    print('\n ***   清除-模块 ***')

class Test_错误密码:

    @classmethod
    def setup_class(cls):
        print('\n === 初始化-类 ===')

    @classmethod
    def teardown_class(cls):
        print('\n === 清除 - 类 ===')
        
    def test_C001001(self):
        print('\n用例C001001')
        assert 1 == 1
        
    def test_C001002(self):
        print('\n用例C001002')
        assert 2 == 2
        
    def test_C001003(self):
        print('\n用例C001003')
        assert 3 == 2

class Test_错误密码2:

    def test_C001021(self):
        print('\n用例C001021')
        assert 1 == 1
        
    def test_C001022(self):
        print('\n用例C001022')
        assert 2 == 2

执行命令 python -m pytest cases -s ,运行结果如下

collected 5 items

cases\登录\test_错误登录.py
 *** 初始化-模块 ***

 === 初始化-类 ===

用例C001001
.
用例C001002
.
用例C001003
F
 === 清除 - 类 ===

用例C001021
.
用例C001022
.
 ***   清除-模块 ***

可以发现,类级别的初始化、清除 在 整个类 所有用例 执行前后 分别 执行1次

它主要是用来为该 中的所有测试用例做 公共的 初始化 和 清除

方法级别

方法级别 的初始化、清除 分别 在类的 每个测试方法 执行前后执行,并且 每个用例分别执行1次

如下定义 setup_method 和 teardown_method 实例方法

def setup_module():
    print('\n *** 初始化-模块 ***')

def teardown_module():
    print('\n ***   清除-模块 ***')

class Test_错误密码:

    @classmethod
    def setup_class(cls):
        print('\n === 初始化-类 ===')

    @classmethod
    def teardown_class(cls):
        print('\n === 清除 - 类 ===')
        
    def setup_method(self):
        print('\n --- 初始化-方法  ---')

    def teardown_method(self):
        print('\n --- 清除  -方法 ---')
        
    def test_C001001(self):
        print('\n用例C001001')
        assert 1 == 1
        
    def test_C001002(self):
        print('\n用例C001002')
        assert 2 == 2
        
    def test_C001003(self):
        print('\n用例C001003')
        assert 3 == 2

class Test_错误密码2:

    def test_C001021(self):
        print('\n用例C001021')
        assert 1 == 1
        
    def test_C001022(self):
        print('\n用例C001022')
        assert 2 == 2

执行命令 python -m pytest cases -s ,运行结果如下

collected 5 items

cases\登录\test_错误登录.py
 *** 初始化-模块 ***

 === 初始化-类 ===

 --- 初始化-方法  ---

用例C001001
.
 --- 清除  -方法 ---

 --- 初始化-方法  ---

用例C001002
.
 --- 清除  -方法 ---

 --- 初始化-方法  ---

用例C001003
F
 --- 清除  -方法 ---

 === 清除 - 类 ===

用例C001021
.
用例C001022
.
 ***   清除-模块 ***

可以发现,方法级别的初始化、清除 在 整个模块所有用例 执行前后 分别 执行一次

目录级别

目标级别的 初始化清除,就是针对整个目录执行的初始化、清除。

我们在需要初始化的目录下面创建 一个名为 conftest.py 的文件,里面内容如下所示

import pytest 

@pytest.fixture(scope='package',autouse=True)
def st_emptyEnv():
    print(f'\n#### 初始化-目录甲')
    yield
    
    print(f'\n#### 清除-目录甲')

注意:这里清除环境的代码就是 yield 之后的代码。 这是一个生成器,具体的说明参见视频讲解。


我们可以在多个目录下面放置这样的文件,定义该目录的初始化清除。

pytest 在执行测试时,会层层调用。


但是我发现了pytest一个重要的bug: 清除操作并不一定会在该目录最后一个测试用例执行完进行调用。

我已经在github上给pytest 的开发人员提交了bug report, 点击这里查看

在我看来,这个问题是非常大的。

因为,一个目录下的用例执行完后,该清除的数据没有清除,这可能会导致其他目录下的用例执行失败。

所以在这个问题解决前,白月黑羽推荐大家先不要使用这种 目录级别 的初始化清除。

挑选用例执行

点击这里,边看视频讲解,边学习以下内容

pytest 可以灵活的挑选测试用例执行

指定一个模块

可以像这样只挑选一个模块执行

python -m pytest cases\登录\test_错误登录.py

指定目录

可以像这样只挑选一个目录执行

python -m pytest cases

也可以指定多个目录

python -m pytest cases1  cases2\登录

指定模块里面的函数或者类

指定一个类

python -m pytest cases\登录\test_错误登录.py::Test_错误密码

也可以指定类里面的方法

python -m pytest cases\登录\test_错误登录.py::Test_错误密码::test_C001001

根据名字

可以使用 命令行参数 -k 后面加名字来挑选要执行的测试项

比如像这样后面跟测试函数名字的一部分:

python -m pytest -k C001001 -s

注意,-k 后面的名字

根据标签

参考官方文档

可以这样给 某个方法加上标签 webtest

import pytest

class Test_错误密码2:

    @pytest.mark.webtest
    def test_C001021(self):
        print('\n用例C001021')
        assert 1 == 1

然后,可以这样运行指定标签的用例

python -m pytest cases -m webtest -s

也可以这样给整个类加上标签

@pytest.mark.webtest
class Test_错误密码2:

    def test_C001021(self):
        print('\n用例C001021')
        assert 1 == 1

当然标签也支持中文

@pytest.mark.网页测试
class Test_错误密码2:

    def test_C001021(self):
        print('\n用例C001021')
        assert 1 == 1

然后,运行命令行指定标签

python -m pytest cases -m 网页测试 -s

可以这样同时添加多个标签

@pytest.mark.网页测试
@pytest.mark.登录测试
class Test_错误密码2:

    def test_C001021(self):
        print('\n用例C001021')
        assert 1 == 1

可以这样定义一个全局变量 pytestmark 为 整个模块文件 设定标签

import pytest
pytestmark = pytest.mark.网页测试

如果你需要定义多个标签,可以定义一个列表

import pytest
pytestmark = [pytest.mark.网页测试, pytest.mark.登录测试]

自定义的标签,运行时,pytest会有告警。

可以在项目根目录下创建配置文件 pytest.ini 并且在里面设置标签配置项

如下:

[pytest]
markers =
    critical: critical tests
    网页测试: 标记为网页测试

冒号后面的是 标签 的说明。

Pytest 助手

我开发了一个助手软件, 方便 挑选用例,查看运行过程,产生测试报告。

就是下一章的内容,点击这里查看

实战案例

点击这里,边看视频讲解,边学习以下内容

下面我们以 白月SMS 系统 为被测系统,使用 pytest 进行自动化测试

请大家点击这里,按照说明下载、安装、运行 白月SMS系统

点击这里下载 白月SMS系统的测试用例文档

请观看视频讲解,如何使用 pytest,完成用例 UI-0001UI-0005 的自动化


案例视频中说明了,在自动化项目中,我们的测试用例经常需要导入项目目录的库文件,我们需要这样执行命令

python -m pytest cases -sv

因为 -m 这种执行模块的方式运行python, 会自动把当前工作目录作为模块搜索路径,

这样就能避免Python解释器 搜索不到 库文件的问题 ModuleNotFoundError: No module named 'xxxx'


视频教程最后的自动化代码如下

# autotest\cases\登录\test_错误登录.py
import pytest
from lib.webui import loginAndCheck

class Test_错误登录:

    def test_UI_0001(self):
        alertText = loginAndCheck(None,'88888888')
        assert alertText == '请输入用户名'


    def test_UI_0002(self):
        alertText = loginAndCheck('byhy',None)
        assert alertText == '请输入密码'

    def test_UI_0003(self):
        alertText = loginAndCheck('byh','88888888')
        assert alertText == '登录失败 : 用户名或者密码错误'

# lib\webui.py
from selenium import webdriver
import time

def loginAndCheck(username,password):
    driver = webdriver.Chrome()
    driver.implicitly_wait(10)

    driver.get('http://127.0.0.1/mgr/sign.html')

    if username is not None:
        driver.find_element_by_id('username').send_keys(username)

    if password is not None:
        driver.find_element_by_id('password').send_keys(password)

    driver.find_element_by_css_selector("button[type='submit']").click()

    time.sleep(2)

    alertText = driver.switch_to.alert.text
    print(alertText)

    driver.quit()

    return alertText

数据驱动

点击这里,边看视频讲解,边学习以下内容

用例 UI-0001UI-0005 这5个登录的测试用例,共同的特点是,它们测试步骤是一模一样的,只是输入的数据(用户名、密码)不同,要检查的输出数据(错误提示)不同。

这批测试用例,就是典型的 可以用 数据驱动 方式进行自动化的用例。

如果有一批测试用例,具有 相同的测试步骤 ,只是 测试参数数据不同

自动化测试时,把测试数据从用例代码中 分离 开来,以后增加新的测试用例,只需要修改数据。

这就是数据驱动。


这种情况可以使用 pytest 用例 的 数据驱动格式,只需如下定义即可

class Test_错误登录:
    @pytest.mark.parametrize('username, password, expectedalert', [
        (None, '88888888', '请输入用户名'),
        ('byhy', None, '请输入密码'),
        ('byh', '88888888', '登录失败 : 用户名或者密码错误'),
        ('byhy', '8888888', '登录失败 : 用户名或者密码错误'),
        ('byhy', '888888888', '登录失败 : 用户名或者密码错误'),
    ]
                             )
    def test_UI_0001_0005(self, username, password, expectedalert):
        alertText = loginAndCheck(username, password)
        assert alertText == expectedalert

这样,我们就不需要定义那么多的测试用例方法了, 而且测试数据也可以集中存放。

更多细节,参考pytest官方文档


您需要高效学习,找工作? 点击这里 白月黑羽实战班


调试

当我们需要调试代码时,可以添加断点,然后按照下图所示

  1. 点击打开运行配置

  2. 点击+号, 添加一个运行配置,在右边的输入框输入配置名,比如 pytest

  3. 点击箭头选择 module name,并且输入 pytest 作为运行模块名

  4. 参数输入相应的命令行参数,比如 cases -sv

  5. 工作目录选择项目根目录

  6. 点击 OK

使用 fixture

前面讲初始化清除时,主要用的是 unittest 风格的初始化清除方法。

pytest里面有更灵活方便的初始化、清除 方法,就是使用 fixture


使用方法

相比前面讲的初始化清除方法,fixture 最大的特点是:声明式使用

就是:测试方法需要那个初始化清除,就在参数里面声明它

比如:

import pytest

# 定义一个fixture函数
@pytest.fixture
def createzhangSan():
    # 这里代码实现了使用API创建用户张三账号功能
    print('\n *** createzhangSan ***')
    zhangSan = {
        'username'   : 'zhangsan',
        'password'   : '111111',
        'invitecode' : 'abcdefg' # 这是系统创建用户产生的其它信息
    }
    return zhangSan


# 这里测试张三账号登录的功能
def test_A001001(createzhangSan):
    print('\n用例 A001001')
    print('\ninvitecode is', createzhangSan['invitecode'])


# 这里测试其它功能,不需要张三账号
def test_C001001():
    print('\n用例 C001001')

把上面的代码保存到文件,命令行进入该文件所在目录,执行 python -m pytest -sv

结果如下:

collected 2 items

test_1.py::test_A001001
 *** createzhangSan ***

用例 A001001

invitecode is abcdefg
PASSED

test_1.py::test_C001001
用例 C001001
PASSED


可以发现,test_A001001 用例函数参数 里面申明了要使用 createzhangSan 这个fixture,就会在执行该用例函数前 先执行createzhangSan 这个 fixture 函数

而 test_A001001 用例函数参数里面没有申明要使用 fixture,当然执行该用例,就不会执行 fixture 函数。


可能大家最费解的是: 参数名和fixutre 函数同名,就会自动执行它, 这和我们以往理解的python不一样啊。

是的,这就是 pytest 的 denpendcy injection 中文称之为 : 依赖注入

不要被这些名词吓懵了,这就是pytest的做法而已。

我们的测试函数 都是 pytest 搜集和调用的,pytest会做这样的分析:

如果发现 测试函数参数 和 某个 fixture 同名,就知道:

要在执行该测试时先调用该 fixture函数, 然后把fixture函数返回的结果 作为 调用测试函数该参数的值。

仅此而已,所谓依赖注入,没有什么神秘的。

清除

上面的示例只讲了初始化,没有说清除操作如何执行,

如果需要清除,最推荐的使用 yield 代替 return , yield后面的代码就是清除部分的代码。

比如

import pytest

# 定义一个fixture函数
@pytest.fixture
def createzhangSan():
    print('\n ***  执行创建张三账号的代码 ***')
    zhangSan = {
        'username'   : 'zhangsan',
        'password'   : '111111',
        'invitecode' : 'abcdefg' # 这是系统创建用户产生的其它信息
    }

    yield zhangSan

    print('\n ***  执行清除张三账号的代码 ***')

def test_A001001(createzhangSan):
    print('\n用例 A001001')
    print('\ninvitecode is', createzhangSan['invitecode'])

运行结果如下

test_1.py::test_A001001
 ***  执行创建张三账号的代码 ***

用例 A001001

invitecode is abcdefg
PASSED
 ***  执行清除张三账号的代码 ***

fixture 参数

如果我们要使用的fixture本身行为需要参数,怎么办?

比如, 前面的例子中,如果fixture初始创建的不是固定的张三用户,而是需要根据参数来创建不同的用户,怎么做呢?

这时就需要使用 parametrize 装饰器,并指定参数 indirect=True

如下所示:


import pytest

# 定义一个fixture函数
@pytest.fixture
def createUser(request):
    # 这里代码实现了使用API创建用户账号功能
    print('\n *** createUser ***')
    user = {
        'username'   : request.param[0],
        'password'   : request.param[1],
        'invitecode' : 'abcdefg' # 这是系统创建用户产生的其它信息
    }
    return user


@pytest.mark.parametrize("createUser",
                         [("zhangsan", "111")],
                         indirect=True)
def test_A001001(createUser):
    print('\n用例 A001001')
    print('\nusername is', createUser['username'])
    print('测试行为1111')

@pytest.mark.parametrize("createUser",
                         [("lisi", "111")],
                         indirect=True)
def test_A001002(createUser):
    print('\n用例 A001002')
    print('\nusername is', createUser['username'])
    print('测试行为2222')

其中 createUser 里面的request是特殊的名字,是pytest内置的fixture SubRequest对象

这个对象的param属性是一个tuple,里面保存了传入的一个个参数


把上面的代码保存到文件,命令行进入该文件所在目录,执行 python -m pytest -sv

结果如下:

collected 2 items

test_1.py::test_A001001[createUser0]
 *** createUser ***

用例 A001001

username is zhangsan
测试行为1111
PASSED


test_1.py::test_A001002[createUser0]
 *** createUser ***

用例 A001002

username is lisi
测试行为2222
PASSED


当然,如果多个测试函数的代码都一样,就是前面说的数据驱动,

用例函数可以合并起来,使用多个参数,像这样

@pytest.mark.parametrize("createUser",
    [("zhangsan", "111111"),("lisi", "111")],
    indirect=True)
def test_A00100X(createUser):
    print('\nusername is', createUser['username'])
    print('测试行为')

scope 范围

fixture 由小到大,有下面这几种级别范围

会在测试函数结束时执行 fixture 对应的清除

会在 类 里面的最后一个测试方法 结束时 执行 fixture 对应的清除

会在 模块文件 里面的最后一个测试方法 结束时 执行 fixture 对应的清除

会在 目录 里面的最后一个测试方法 结束时 执行 fixture 对应的清除

会在 整个测试 的最后一个测试方法 结束时 执行 fixture 对应的清除

函数级别

函数级别 的fixture ,初始化、清除 会再每个函数或者方法执行前面各调用一次

fixture 的 scope 缺省值 ,就是 function , 所以也可以不指定

import pytest

@pytest.fixture(scope='function')
def createzhangSan():
    print('\n ***  创建 ***')
    zhangSan = {
        'username'   : 'zhangsan',
        'password'   : '111111',
    }

    yield zhangSan

    print('\n ***  清除 ***')


class Test_C:

    def test_C001(self, createzhangSan):
        print('\n用例C001')

    def test_C002(self, createzhangSan):
        print('\n用例C002')


class Test_D:

    def test_D001001(self, createzhangSan):
        print('\n用例D001')

执行命令 pytest cases -sv ,运行结果如下

collected 3 items  


test_1.py
 ***  创建 ***

用例C001
.
 ***  清除 ***

 ***  创建 ***

用例C002
.
 ***  清除 ***



 ***  创建 ***

用例D001
.
 ***  清除 ***


可以发现,在所有使用该fixture的方法,前后 分别会调用一次。

类级别

类级别 的初始化、清除 分别 在整个类的测试用例 执行前后执行,并且 只会执行1次

前面的代码,只修改一下 scope 值为 class ,其它代码不变

@pytest.fixture(scope='class')
def createzhangSan():

执行命令 pytest cases -s ,运行结果如下

collected 3 items

test_1.py::Test_C::test_C001
 ***  执行创建张三账号的代码 ***

test_1.py
 ***  创建 ***

用例C001
.
用例C002
.
 ***  清除 ***



 ***  创建 ***

用例D001
.
 ***  清除 ***


可以发现,

Test_C 这个类里面,虽然2个方法都声明要使用 createzhangSan,但是只执行了1次,

因为这个fixture的 scope 是 class


所以,类级别的初始化、清除 在 整个类所有用例 执行前后 分别 执行1次

它主要是用来为该 中的所有测试用例做 公共的 初始化 和 清除

模块级别

模块级别 的初始化、清除 分别 在模块的 所有测试方法 执行前后执行,并且 只执行1次


前面的代码,只修改一下 scope 值为 module ,其它代码不变

@pytest.fixture(scope='module')
def createzhangSan():

执行命令 pytest cases -s ,运行结果如下

collected 3 items

test_1.py
 ***  创建 ***

用例C001
.
用例C002
.
用例D001
.
 ***  清除 ***

可以发现,模块级别的初始化、清除 在 整个模块所有用例 执行前后 分别 只执行一次

目录级别

目录级别的 初始化清除,就是针对整个目录执行的初始化、清除。

目录级别的初始化、清除 在 整个目录 所有用例 执行前后 分别 只执行一次


我们在需要针对的目录下面创建 一个名为 conftest.py 的文件,里面内容如下所示

import pytest 

@pytest.fixture(scope='package',autouse=True)
def st_emptyEnv():
    print(f'\n#### 初始化-目录甲')
    yield
    
    print(f'\n#### 清除-目录甲')

我们再创建另外2个文件 test_1.py, test_2.py ,内容如下

# test_1.py 内容
class Test_C:

    def test_C001(self):
        print('\n用例C001')

    def test_C002(self):
        print('\n用例C002')


class Test_D:

    def test_D001001(self):
        print('\n用例D001')
# test_2.py 内容
class Test_E:

    def test_E001(self):
        print('\n用例E001')

    def test_E002(self,):
        print('\n用例E002')

执行命令 pytest cases -s ,运行结果如下

collected 5 items

test_1.py
#### 初始化-目录甲

用例C001
.
用例C002
.
用例D001
.
test_2.py
用例E001
.
用例E002
.
#### 清除-目录甲

可以发现,目录级别的初始化、清除 在 整个目录 所有用例 执行前后 分别 只执行一次

而且,使用conftest里面的fixture ,我们不需要在用例模块中 import 导入该fixture


我们可以在多个目录下面放置这样的文件,定义该目录的初始化清除。

pytest 在执行测试时,会层层调用。


整个测试级别

整个测试级别的 初始化清除,就是针对 整个测试 执行的初始化、清除。

整个测试级别的初始化、清除 在 整个测试 所有用例 执行前后 分别 只执行一次


前面的示例,我们只修改一下 scope 值为 session ,其它代码不变

测试结果也是一样的。

自动使用 fixture

前面的fixture示例,都需要 用例函数 在参数里面 申明使用,才会调用的。

如果没有用例 声明使用,就不会调用这个fixture。


如果,我们想不声明,就默认使用,可以指定fixture的参数 autouse 的值为 true

比如

import pytest

@pytest.fixture(scope='module', autouse=True)
def createzhangSan():
    print('\n ***  创建数据环境 ***')

    yield

    print('\n ***  清除数据环境 ***')


def test_C001():
    print('\n用例C001')


def test_C002():
    print('\n用例C002')

这种自动使用fixture的情况,通常是 fixture 没有返回值 需要给用例使用的情况。

项目实战

Elife 是一个 互联网生活服务系统。

我们使用 pytest 实现一些测试用例的自动化。

点击这里观看 使用说明视频


点击这里打开网盘

根据视频讲解,下载 系统安装包和测试用例,并运行 Elife-RC


系统管理端网站登录网址是 http://主机地址:8234

比如: http://127.0.0.1:8234

系统超级管理员账号是 byhy , 缺省密码是 sdfsdf


请使用 pytest 完成 用例文档中 测试用例 的自动化