【无标题】

Pytest框架

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

  • 用 Python 编写测试用例,简便易用

  • 可以用 文件系统目录层次 对应 手工测试用例 层次结构

  • 灵活的 初始化清除 机制

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

  • 利用第三方插件,可以生成美观的可视化的报表

一、安装Pytest

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

pip install pytest 

二、快速上手

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

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

  • 如果未指定命令行参数,则从 testpath(如果已配置)或当前目录开始收集。

  • 如果命令行参数, 指定了 目录、文件名 或 node id 的任何组合,则按参数来找

  • 寻找过程会递归到目录中,除非它们匹配上 norecursedirs。

  • 在这些目录中,搜索由其测试包名称导入的 test_*.py*_test.py 文件。

  • 从这些文件中,收集如下测试项:

    • test为前缀 的 函数

    • Test为前缀的 里面的 test为前缀的方法

2.2.测试用例代码

编写的测试用例代码文件, 必须以 test_ 开头,或者以 _test 结尾,比如,我们创建一个 文件名为 test1.py ,放在目录 autotest\下面。

内容如下:

class Test_pass:
    def test_01(self):
        print('\n用例01')
        assert 1 == 1
​
    def test_02(self):
        print('\n用例02')
        assert 2 == 2
​
    def test_03(self):
        print('\n用例03')
        assert 3 == 2

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

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

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

2.3.运行测试

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

上面的示例执行结果如下

img

显示找到3个测试项,2个执行通过,1个不通过。通过的用例 是用一个小点表示, 不通过的用例用一个F表示,并且会在后面显示具体不通过的用例 和不通过的检查点 代码细节。

pytest 不会使用print打印的内容。如果我们希望 显示测试代码中print的内容,因为这些打印语句在调试代码时很有用,可以加上命令行参数 -s,例如:
pytest -s ./autotest/test1.py

img

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

img

执行 pytest 时, 如果命令行没有指定目标目录 或者 文件, 它会自动搜索当前目录下所有符合条件的文件、类、函数。为了防止 pytest 到其他目录中找测试用例项,执行测试时,我们可以在命令行加上目标目录名字 ,就像上面这样:

#指定是从项目根目录下的autotest中查找执行
pytest -sv ./autotest/test1.py

2.4.产生报告

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

pip install pytest-html

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

pytest ./autotest/test1.py --html=report.html --self-contained-html

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

三、初始化清除

3.1.模块级别

模块级别 的初始化、清除 分别 在整个模块的测试用例 执行前后执行,并且 只会执行1次 。如下定义 setup_module 和 teardown_module 全局函数

img

可以发现,模块级别的初始化、清除 在 整个模块所有用例 执行前后 分别 执行1次,它主要是用来为该 模块 中 所有的测试用例做 公共的 初始化清除

3.2.类级别

类级别 的初始化、清除 分别 在整个类的测试用例 执行前后执行,并且 只会执行1次,如下定义 setup_class 和 teardown_class 类方法:

def setup_module():
    print('\n *** 初始化-模块 ***')
​
def teardown_module():
    print('\n *** 清除-模块 ***')
​
class Test_pass:
    @classmethod
    def setup_class(cls):
        print("\n === Test_pass初始化-类 ===")
​
    @classmethod
    def teardown_class(cls):
        print('\n === Test_pass清除-类 ===')
​
    def test_C001001(self):
        print('\n用例1')
        assert 1 == 1
​
    def test_C001002(self):
        print('\n用例2')
        assert 2 == 2
​
    def test_C001003(self):
        print('\n用例3')
        assert 3 == 2
​
class Test_pass1:
    @classmethod
    def setup_class(cls):
        print("\n === Test_pass1初始化-类 ===")
​
    @classmethod
    def teardown_class(cls):
        print('\n === Test_pass1清除-类 ===')
​
    def test_11(self):
        print('\n用例11')
        assert 4 == 4
​
    def test_22(self):
        print('\n用例22')
        assert 34 == 34
​
    def test_33(self):
        print('\n用例33')
        assert 3 == 3.0

执行命令 pytest -s test1.py ,运行结果如下

img

可以发现,类级别的初始化、清除 在 整个模块每一个类的用例 执行前后 分别 执行1次 。它主要是用来为该 中的所有测试用例做 公共的 初始化 和 清除

3.3.方法级别

方法级别 的初始化、清除 分别 在类的 每个测试方法 执行前后执行,并且 每个用例分别执行1次,如下定义 setup_method 和 teardown_method 实例方法:

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

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

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

    @classmethod
    def teardown_class(cls):
        print('\n === Test_pass清除-类 ===')

    def setup_method(self):
        print('\n --- 初始化-方法  ---')

    def teardown_method(self):
        print('\n --- 清除-方法 ---')

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

    def test_C001002(self):
        print('\n用例2')
        assert 2 == 2

    def test_C001003(self):
        print('\n用例3')
        assert 3 == 2

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

    @classmethod
    def teardown_class(cls):
        print('\n === Test_pass1清除-类 ===')

    def test_11(self):
        print('\n用例11')
        assert 4 == 4

    def test_22(self):
        print('\n用例22')
        assert 34 == 34

    def test_33(self):
        print('\n用例33')
        assert 3 == 3.0

执行命令 pytest -s test1.py ,运行结果如下:

img

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

3.4.目录级别

目标级别的 初始化清除,就是针对整个目录执行的初始化、清除。需要初始化的目录下面创建 一个名为 conftest.py 的文件,里面内容如下所示

import pytest

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

注意:这里清除环境的代码就是 yield 之后的代码。 这是一个生成器。我们可以在多个目录下面放置这样的文件,定义该目录的初始化清除。pytest 在执行测试时,会层层调用。

四、挑选用例执行

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

4.1.指定一个模块

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

pytest autotest\test1.py

4.2.指定目录

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

pytest autotest

也可以指定多个目录

pytest autotest  autotest1

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

指定一个类

pytest autotest\test_01.py::Test_pass

也可以指定类里面的方法

pytest autotest\test_01.py::Test_pass::test_02

4.4.根据名字

可以使用 命令行参数 -k 后面加名字来挑选要执行的测试项,比如像这样后面跟测试函数名字的一部分:

pytest -k test_33 -s

注意,-k 后面的名字

  • 可以是测试函数的名字,可以是类的名字,可以是模块文件名,可以是目录的名字

  • 是大小写敏感的

  • 不一定要完整,只要能有部分匹配上就行

  • 可以用 not 表示选择名字中不包含,比如

    pytest -k "not test_33" -s
  • 可以用 and 表示选择名字同时包含多个关键字,比如

    pytest -k "33 and test" -s
  • 可以用 or 表示选择名字 包含指定关键字之一即可,比如

    pytest -k "33 or test" -s

4.5.根据标签

参考官方文档

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

import pytest
class Test_pass1:
    @pytest.mark.weblogintest
    def test_11(self):
        print('\n用例11')
        assert 4 == 4

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

pytest autotest -m weblogintest -s

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

@pytest.mark.weblogintest
class Test_pass1:

    def test_11(self):
        print('\n用例11')
        assert 4 == 4

    def test_22(self):
        print('\n用例22')
        assert 34 == 34

    def test_33(self):
        print('\n用例33')
        assert 3 == 3.0

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

@pytest.mark.weblogintest
@pytest.mark.webapilogintest
class Test_pass1:

    def test_11(self):
        print('\n用例11')
        assert 4 == 4

    def test_22(self):
        print('\n用例22')
        assert 34 == 34

    def test_33(self):
        print('\n用例33')
        assert 3 == 3.0

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

import pytest
pytestmark = pytest.mark.login

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

import pytest

pytestmark = [pytest.mark.login, pytest.mark.weblogintest, pytest.mark.webapilogintest]

4.6Pytest 跳过

使用跳过装饰器 @pytest.mark.skip,我们可以跳过指定的测试。 跳过测试有多种原因。 例如,数据库/在线服务目前不可用

import pytest

class Test_add():

    @classmethod
    def setup_class(cls):
        print("***************类级别的初始化*************")

    @classmethod
    def teardown_class(cls):
        print("***************类级别的清除*************")

    def setup_method(self):
        print("***************用例级别的初始化*************")

    def teardown_method(self):
        print("***************用例级别的清除*************")

    def test_02(self):
        print("这是 test_02")
        assert 3 > 2

    @pytest.mark.skip
    def test_03(self):
        print("这是 test_03")
        assert 3 in [34, 2, 3]

在示例中,test_03()被跳过,不会执行

五、数据驱动

有这样一个场景,登录的测试用例,共同的特点是,它们测试步骤是一模一样的,只是输入的数据(用户名、密码)不同,要检查的输出数据(错误提示)不同。这批测试用例,就是典型的 可以用 数据驱动 方式进行自动化的用例。如果有一批测试用例,具有 相同的测试步骤 ,只是 测试参数数据不同 。自动化测试时,把测试数据从用例代码中 分离 开来,以后增加新的测试用例,只需要修改数据。这就是数据驱动。

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

class Test_错误登录:
    @pytest.mark.parametrize('username, password, expectedalert', [
        ('lisi', '88888888', '请输入用户名'),
        ('zhangsan', None, '请输入密码')
    ])
    def test_UI_0005(self, username, password, expectedalert):
        alertText = login(username, password)
        assert alertText == expectedalert

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

六、结合allure生成测试报告

由于pytest-html 生成的测试报告过于简陋,可以借助于allure生成可视化的测试报告更加的美观同时易用性也不错,allure是一个通用的测试报告框架,

6.1.下载allure

下载地址:Allure Report,进入该页面,右上角有个download,点击进入github页面,选择最新版本下载到某个路径下

img

6. 2.安装allure

需要java8+,JDK 1.8+环境,所以提前配置好java环境

将安装包解压后配置allure环境变量,在系统变量path中添加到bin,例如:

D:\allure-2.13.7\bin

配置成功后在命令窗口输入allure或者allure --version,可以看到我的allure版本是2.13.7

img

6.3.在pycharm中下载allure插件

pip install allure-pytest

6.4.allure中常见装饰器

@allure 装饰器中的一些功能点:
@allure.feature :用于定义被测试的功能,被测产品的需求点
@allure.story : 用于定义被测功能的用户场景,即子功能点
@allure.step :用于将一个测试用例,分成几个步骤在报告中输出
@allure.attach : 用于向测试报告中输入一些附加的信息,通常是一些测试数据信息

6.5.使用allure生成测试报告

#获取生成allure测试报告的执行信息
pytest test_case -m webtest --alluredir=./tmp
#生成测试报告
allure generate ./tmp -o ./report --clean

项目中执行实例

import os


data_path = "./outfile/logs"

# 执行命令,将执行信息保存到logs目录
os.system(f'pytest test_case --alluredir={data_path}')

report_path = "./outfile/report"
os.system(f'allure generate {data_path} -o {report_path} --clean')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值