pytest: Python的一个单元测试框架,基于UnitTest二次开发,语法上更加简洁,可以用来做Python开发项目的单元测试,UI自动化、接口自动化测试等,有很多的插件访问Pytest插件汇总,对Pytest进行扩展。

pytest是一个框架,它使构建简单且可伸缩的测试变得容易。测试具有表达性和可读性,不需要样板代码。在几分钟内开始对应用程序或库进行小的单元测试或复杂的功能测试。 -- 来自Pytest官方文档(由谷歌翻译)

https://docs.pytest.org/en/latest/parametrize.html

安装

pip install pytest

文件名称规则

与UnitTest类似,测试文件名称需要以test_文件名.py(推荐使用这种)或者文件名_test.py格式。

测试类的名称:Test类名来定义一个测试类

测试方法(函数):test_方法名来定义一个测试方法

#!/usr/bin/env/python3
# -*- coding:utf-8 -*-
"""
@project: pytest_study
@author: zy7y
@file: test_01.py
@ide: PyCharm
@time: 2020/7/27
"""
# 测试类TestNumber
class TestNumber(object):
def __int__(self):
pass def test_sum(self):
# assert进行断言
assert 1 == 2 def test_str(self):
# isinstance 判断对象是否为对应类型
assert isinstance(1, int)

运行测试

方法1:在当前目录下使用命令行,输入pytest将会执行该目录下所有test_*.py文件

(venv) bogon:pytest_study zy7y$ pytest
========================================================================= test session starts =========================================================================
platform darwin -- Python 3.8.3, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: /Users/zy7y/PycharmProjects/pytest_study
collected 3 items test_01.py F. # F.为测试失败 [ 66%]
test_02.py . # . 为测试通过 [100%] ============================================================================== FAILURES ===============================================================================
_________________________________________________________________________ TestNumber.test_sum _________________________________________________________________________ self = <test_01.TestNumber object at 0x1110fb580> def test_sum(self):
# assert进行断言
> assert 1 == 2
E assert 1 == 2 test_01.py:19: AssertionError
======================================================================= short test summary info =======================================================================
FAILED test_01.py::TestNumber::test_sum - assert 1 == 2
===================================================================== 1 failed, 2 passed in 0.07s =====================================================================

方法2: 在当前目录下使用命令行,输入pytest test_*.py指定运行某个测试文件

(venv) bogon:pytest_study zy7y$ pytest test_01.py
F. [100%]
============================================================================== FAILURES ===============================================================================
_________________________________________________________________________ TestNumber.test_sum _________________________________________________________________________ self = <test_01.TestNumber object at 0x10824aac0> def test_sum(self):
# assert进行断言
> assert 1 == 2
E assert 1 == 2 test_01.py:19: AssertionError
======================================================================= short test summary info =======================================================================
FAILED test_01.py::TestNumber::test_sum - assert 1 == 2
1 failed, 1 passed in 0.06s

方法3:在测试文件下使用pytest.main()方法来运行.

#!/usr/bin/env/python3
# -*- coding:utf-8 -*-
"""
@project: pytest_study
@author: zy7y
@file: test_01.py
@ide: PyCharm
@time: 2020/7/27
""" # 测试类TestNumber
class TestNumber(object):
def __int__(self):
pass def test_sum(self):
# assert进行断言
assert 1 == 2 def test_str(self):
assert isinstance(1, int) if __name__ == '__main__':
import pytest
# 相当于在命令行当前目录中执行了 pytest
pytest.main() # 执行pytest -q test_01.py : -q 简短输出测试信息
pytest.main(['-q', 'test_01.py'])

方法4:使用Pycharm修改单元测试框架来启动单个测试文件.

![image-20200727155705065](/Users/zy7y/Library/Application Support/typora-user-images/image-20200727155705065.png)

![image-20200727155814350](/Users/zy7y/Library/Application Support/typora-user-images/image-20200727155814350.png)

临时目录

pytest提供内置的fixtures / function参数来请求任意资源,例如唯一的临时目录:

在测试函数签名中列出名称tmpdir,pytest将在执行测试函数调用之前查找并调用夹具工厂来创建资源。 在测试运行之前,pytest创建一个“每次测试调用唯一”临时目录

#!/usr/bin/env/python3
# -*- coding:utf-8 -*-
"""
@project: pytest_study
@author: zy7y
@file: test_02.py
@ide: PyCharm
@time: 2020/7/27
""" def test_02():
assert 1 == 1 # 临时目录
def test_neddsfiles(tmpdir):
# 打印临时目录地址
print(tmpdir) # tmpdir = local('/private/var/folders/m4/gq5zy91j62x8qx_msq5mdbxw0000gn/T/pytest-of-zy7y/pytest-7/test_neddsfiles0') # 0 和 None 、 '' 在python中属于 False
assert None

pytest其他命令

命令行中执行:
pytest --fixtures # 显示内置和自定义 fixtures
pytest -h # 查看帮助
pytest -x # 第一次故障后停止测试
pytest --maxfail=2 # 2次失败后停止 运行测试方法:
pytest test_*.py # 在模块中运行测试(运行整个.py下的测试类、方法、函数)
pytest testing/ # 在工作目录运行测试(运行指定文件目录下的所有测试类、方法、函数) pytest -k "Number and not str" # 关键字运行
这将运行包含与给定字符串表达式(大小写不敏感)匹配的名称的测试,其中可以包括使用文件名、类名和函数名作为变量的Python操作符。上面的示例将运行TestNumber。测试一些东西,但不运行test_str测试方法。 pytest test_02.py::test_02 # 在模块中运行测试,就是说运行test_02.py文件中test_02的函数 pytest test_01.py::TestNumber::test_sum # 运行模块下指定测试类的测试方法 pytest -m slow # 将运行所有用@pytest.mark.slow装饰的测试 pytest --pyargs pkg.testing # 运行文件名称为testing的包下面所有的测试文件

fixture(依赖注入)

注意: Pytest对于每个fixture只会缓存一个实例,这意味着如果使用参数化的fixture,pytest可能会 比定义的作用域更多次的调用fixture函数(因为需要创建不同参数的fixture)

  • 作为函数入参的fixture

    """
    @project: pytest_study
    @author: zy7y
    @file: test_03.py
    @ide: PyCharm
    @time: 2020/7/27
    """ import pytest # 其他测试函数传入这个函数名称时会得到一个实例对象,且一直都是这个实例对象
    @pytest.fixture
    def get_driver():
    from selenium import webdriver
    # 返回一个操控Chrome浏览器的驱动实例 driver
    driver = webdriver.Chrome()
    return driver def test_browse(get_driver):
    get_driver.get("http://www.baidu.com")
    print(id(get_driver)) def test_close(get_driver):
    get_driver.close()
    print(id(get_driver))
  • 在类/模块/中共享fixture实例

    将fixture函数放在独立的conftest.py文件中,可以达到在多个测试模块中访问使用这个fixture;将scope="module"参数添加到@pytest.fixture中

    # conftest.py
    #!/usr/bin/env/python3
    # -*- coding:utf-8 -*-
    """
    @project: pytest_study
    @author: zy7y
    @file: conftest.py
    @ide: PyCharm
    @time: 2020/7/27
    """ import pytest
    @pytest.fixture(scope='module')
    def browse_driver():
    from selenium import webdriver
    # 返回一个操控Chrome浏览器的驱动实例 driver
    driver = webdriver.Chrome()
    return driver
    # test_04.py
    #!/usr/bin/env/python3
    # -*- coding:utf-8 -*-
    """
    @project: pytest_study
    @author: zy7y
    @file: test_04.py
    @ide: PyCharm
    @time: 2020/7/27
    """ def test_open_browse(browse_driver):
    browse_driver.get("https://www.baidu.com") def test_open_blog(browse_driver):
    import time
    time.sleep(3)
    browse_driver.get("https://www.baidu.com")
    print(browse_driver.window_handles)
    browse_driver.close()
  • fixture结束/执行清理代码

    # 修改后的conftest.py
    import pytest
    @pytest.fixture(scope='module')
    def browse_driver():
    # from selenium import webdriver
    # # 返回一个操控Chrome浏览器的驱动实例 driver
    # driver = webdriver.Chrome()
    # return driver # 调用结束/执行清理代码
    from selenium import webdriver
    driver = webdriver.Chrome()
    # 调用前 会实例一个 driver, 然后通过yield 返回
    yield driver
    # 用例结束后使用close关闭driver
    driver.close()
    # test_05.py
    #!/usr/bin/env/python3
    # -*- coding:utf-8 -*-
    """
    @project: pytest_study
    @author: zy7y
    @file: test_05.py
    @ide: PyCharm
    @time: 2020/7/27
    """ def test_open_browse(browse_driver):
    browse_driver.get("https://www.baidu.com")
    assert browse_driver.title == '百度一下,你就知道' def test_open_blog(browse_driver):
    import time
    time.sleep(3)
    browse_driver.get("https://www.cnblogs.com/zy7y/")
    assert 'zy7y' in browse_driver.title
  • fixture固件作用域

    在定义固件时,通过 scope 参数声明作用域,可选项有: function: 函数级,每个测试函数都会执行一次固件; class: 类级别,每个测试类执行一次,所有方法都可以使用; module: 模块级,每个模块执行一次,模块内函数和方法都可使用; session: 会话级,一次测试只执行一次,所有被找到的函数和方法都可用。 package,表示fixture函数在测试包(文件夹)中第一个测试用例执行前和最后一个测试用例执行后执行一次

    # 启动顺序 session(单元测试集 -> 模块 -> 类 - >方法)

用例初始化(UnitTest的类前运行等方法)

模块级别(setup_module/teardown_module) 全局的 函数级别(setup_function/teardown_function) 只对函数用例生效(不在类中的) 类级别 (setup_class/teardown_class) 只在类中前后运行一次(只在类中才生效) 方法级别 (setup_method/teardown_method) 开始后与方法始末(在类中) 类内用例初始化结束 (setup/teardown) 运行在测试用例的前后

import pytest

def setup_module():
print('\nsetup_module 执行') def teardown_module():
print('\nteardown_module 执行') def setup_function():
"""函数方法(类外)初始化"""
print('setup_function 执行') def teardown_function():
"""函数方法(类外)初始化"""
print('\nteardown_function 执行') def test_in_class():
"""类(套件)外的测试用例"""
print('类外测试用例') class Test_clazz(object):
"""测试类""" def setup_class(self):
print('setup_class 执行') def teardown_class(self):
print('teardown_class 执行') def setup_method(self):
print('setup_method 执行') def teardown_method(self0):
print('teardown_method 执行') def setup(self):
print('\nsetup 执行') def teardown(self):
print('\nteardown 执行') def test_case001(self):
"""测试用例一"""
print('测试用例一') def test_case002(self):
"""测试用例二"""
print('测试用例二')

跳过测试函数

实现部分场景该测试函数不需要执行

# test_07.py
#!/usr/bin/env/python3
# -*- coding:utf-8 -*-
"""
@project: pytest_study
@author: zy7y
@file: test_07.py
@ide: PyCharm
@time: 2020/7/27
"""
import pytest
import sys # 这将强制跳过
@pytest.mark.skip(reason="该测试函数将被跳过")
def test_sum():
assert 1 != 2 def test_count():
assert 1 == 0 # 满足条件才跳过
@pytest.mark.skipif(sys.version_info < (3, 6), reason="版本低于3.6将跳过不执行!")
def test_num():
assert 1 + 3 == 5 # 标记测试用例期望失败
@pytest.mark.xfail(reason='期望这个测试是失败的')
def test_func01():
assert 1 == 1

参数化-UnitTest的DDT

内置的pytest.mark.parametrize装饰器可以用来对测试函数进行参数化处理。

#!/usr/bin/env/python3
# -*- coding:utf-8 -*-
"""
@project: pytest_study
@author: zy7y
@file: test_08.py
@ide: PyCharm
@time: 2020/7/27
""" import pytest """
'username, password, expect' 来传递 需要使用到的行参名
[('admin', '123456', '登录成功'), ('admin', '111111', '密码错误')] 来传递对应的实参,这个列表中每一个元组执行一次
ids=["正常登录测试用例标题", "密码错误登录测试用例"] 来传递对应每一次测试的用例标题
这个文件中执行了两次
""" @pytest.mark.parametrize('username, password, expect',
[('admin', '123456', '登录成功'),
('admin', '111111', '密码错误')], ids=["正常登录测试用例标题", "密码错误登录测试用例"])
def test_login(username, password, expect):
if username == 'admin' and password == '123456':
assert expect == '登录成功'
else:
assert expect == '密码错误' # 这将实现两个装饰器的参数组合并且用来测试
@pytest.mark.parametrize("x", [0, 1])
@pytest.mark.parametrize("y", [2, 3])
def test_foo(x, y):
assert x + y == 5

运行脚本,会发生一个字符编码的错误:

解决方法是在 项目根目录下建立一个pytest.ini文件并写入

[pytest]
disable_test_id_escaping_and_forfeit_all_rights_to_community_support = True

Pytest单元测试框架-学习的更多相关文章

  1. Pytest单元测试框架-测试用例运行规则

    1.Pytest测试用例运行规则 在pytest单元测试框架下面执行用例,需要满足以下几个特点: 1. 文件名以test_*.py开头或者*_test.py 2. 测试类.测试函数以test开头 3. ...

  2. Pytest单元测试框架-Pytest环境安装

    unittest是python自带的单元测试框架,它封装好了一些校验返回的结果方法和一些用例执行前的初始化操作,使得单元测试易于开展,因为它的易用性,很多同学也拿它来做功能测试和接口测试,只需简单开发 ...

  3. Pytest单元测试框架:插件-allure-pytest环境搭建并在本地生成一个测试报告

    之前写了allure-pytest的官方文档啃的内容,有些交流的朋友,实践起来没什么头绪,所以就有了这篇文章,也给自己填个坑 第一步:搭建Allure.JDK环境 1. 搭建JDK环境 不装jdk你会 ...

  4. Pytest单元测试框架之简单操作示例

    前言: Pytest是第三方单元格测试框架,更加简单,灵活,而且提供了更多丰富的扩展: Pytest与UnitTest框架的区别 UnitTest测试用例执行顺序是依照ascii码执行,而Pytest ...

  5. Pytest 单元测试框架

    1.pytest 是 python 的第三方单元测试框架,比自带 unittest 更简洁和高效 2.安装 pytest pip install pytest 3.验证 pytest 是否安装成功 p ...

  6. Pytest单元测试框架——Pytest+Allure+Jenkins的应用

    一.简介 pytest+allure+jenkins进行接口测试.生成测试报告.结合jenkins进行集成. pytest是python的一种单元测试框架,与python自带的unittest测试框架 ...

  7. Pytest单元测试框架之FixTure基本使用

    前言: 在单元测试框架中,主要分为:测试固件,测试用例,测试套件,测试执行及测试报告: 测试固件不难理解,也就是我们在执行测试用例前需要做的动作和测试执行后的需要做的事情: 比如在UI自动化测试中,我 ...

  8. pytest单元测试框架

    一.安装方式 1.安装命令:pip install pytest 2.html安装插件:pip install pytest -html 二.pytest执行指定测试用例 1.思想:通过对测试用例进行 ...

  9. Pytest单元测试框架-allure测试报告

    Allure Test Report 对于不同的编程语言,有很多很酷的测试框架.不幸的是,它们中只有少数能够提供测试执行输出的良好表示.Qameta软件测试团队正在致力于Allure--一个开源框架, ...

随机推荐

  1. Report.Net 本地数据库、WebService、Socket报表

    本地.服务器的Access.Sql报表编辑.预览.打印. 可自定义预览界面,可方便嵌入到你的程序中去,提供接口函数,如有需要可自行添加接口. 预览采用单双面方式,因为如果页面过多,预览不能全部加载,所 ...

  2. java IO流 (四) 缓冲流的使用

    1.缓冲流涉及到的类: * BufferedInputStream* BufferedOutputStream* BufferedReader* BufferedWriter 2.作用:作用:提供流的 ...

  3. python 并发专题(十二):基础部分补充(四)协程

    相关概念: 协程:一个线程并发的处理任务 串行:一个线程执行一个任务,执行完毕之后,执行下一个任务 并行:多个CPU执行多个任务,4个CPU执行4个任务 并发:一个CPU执行多个任务,看起来像是同时执 ...

  4. PHP提示dyld: Library not loaded问题解决

    Mac在命令行执行php命令时,如php -v 有错误提示: dyld: Library not loaded: /usr/local/opt/openssl/lib/libcrypto.1.0..d ...

  5. node -v node is not define

    安装node js  踩过的坑 应该是在CMD 命令里执行 node -v 我却傻傻的跑到 node.js 里执行 node -v 结果就报 node is not define 真相如下图!!!

  6. Redis 分布式锁(一)

    前言 本文力争以最简单的语言,以博主自己对分布式锁的理解,按照自己的语言来描述分布式锁的概念.作用.原理.实现.如有错误,还请各位大佬海涵,恳请指正.分布式锁分两篇来讲解,本篇讲解客户端,下一篇讲解r ...

  7. xss小游戏源码分析

    配置 下载地址:https://files.cnblogs.com/files/Lmg66/xssgame-master.zip 使用:下载解压,放到www目录下(phpstudy),http服务下都 ...

  8. 区间dp复习 之 乘积最大

    题目描述 今年是国际数学联盟确定的"2000--世界数学年",又恰逢我国著名数学家华罗庚先生诞辰90周年.在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一 ...

  9. pandas | 如何在DataFrame中通过索引高效获取数据?

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是pandas数据处理专题的第四篇文章,我们一起来聊聊DataFrame中的索引. 上一篇文章当中我们介绍了DataFrame数据结构当 ...

  10. 根据 Promise/A+ 和 ES6 规范,实现 Promise(附详细测试)

    Promise 源码 https://github.com/lfp1024/promise promise-a-plus const PENDING = 'PENDING' const REJECTE ...