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. labelImg安装及使用(YOLO标签为例)

    安装: 非常简单. 第一步: cmd中执行 pip install labelImg 我一般会用下面这个 pip install -i https://pypi.tuna.tsinghua.edu.c ...

  2. LNMP架构应用案例----WordPress

    一.环境部署 mysql        172.16.1.10                                  数据库 web01      10.0.0.11      172.1 ...

  3. PE文件动态加载执行过程

    主要步骤: 1.将要加载的文件读取到内存中(简称为文内),检查文件格式无误后,根据可选PE头(简称op头)的SizeOfImage,申请出一块空间用于存储该文件加载到内存后展开的数据(简称为内内).记 ...

  4. U盘+grub2安装centos8实战

    1. U盘准备 这里的U盘也可以换成硬盘 grub2安装一直失败,怀疑U盘坏了,下面命令修复了一下 [root@host2 ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE ...

  5. Mysql基础(十一):Self Join

    Summary: 如何使用 MySQL self join 进行表的 自己对自己的join操作.. 前面的教程,已经教过join语法,都是两个表的之间的操作,特殊的,当一个表自己和自己进行join,那 ...

  6. Python之爬虫(十四) Scrapy框架的架构和原理

    这一篇文章主要是为了对scrapy框架的工作流程以及各个组件功能的介绍 Scrapy目前已经可以很好的在python3上运行Scrapy使用了Twisted作为框架,Twisted有些特殊的地方是它是 ...

  7. uPDF-功能强大的PDF文件处理小工具

    前几天因为工作原因,需要将一个PDF压缩一下. 网上找了半天,要么收费,要么就是转换的质量不太好.论坛也找到一些破解的软件,但是总有点不太合适,有些功能还挺复杂.也有些在线转换的,又考虑到自己较为隐私 ...

  8. 《重学 Java 设计模式》PDF 出炉了 - 小傅哥,肝了50天写出18万字271页的实战编程资料

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! @ 目录 一.前言 二.简介 1. 谁发明了设计模式? 2. 我怎么学不会设计模式? 3. 适 ...

  9. 理解js中的几种设计模式

    目录 工厂模式 构造函数模式 原型模式 组合使用构造函数模式和原型模式 动态原型模式 其它模式 工厂模式 function createPerson(name, age){ var o = new O ...

  10. 01 安装Linux虚拟机

    平常的工作学习中,Linux成为了一项比不可少的需要的掌握的技能,但是大部分人又不习惯于使用Linux进行生活,所以你需要在你的Windows电脑上安装一个虚拟机,那如何安装呢?其实不难,跟着我一步步 ...