Pytest和Unittest测试框架的区别?

news2024/12/24 21:24:11

如何区分这两者,很简单unittest作为官方的测试框架,在测试方面更加基础,并且可以再次基础上进行二次开发,同时在用法上格式会更加复杂;而pytest框架作为第三方框架,方便的地方就在于使用更加灵活,并且能够对原有unittest风格的测试用例有很好的兼容性,同时在扩展上更加丰富,可通过扩展的插件增加使用的场景,比如一些并发测试等;

Pytest 安装

pip安装:

pip install pytest

测试安装成功:

pytest --help
 
py.test --help

检查安装版本:

pytest --version

Pytest 示例

Pytest编写规则:

  • 测试文件以test_开头(以_test为结尾)
  • 测试的类以Test开头;
  • 测试的方法以test_开头
  • 断言使用基本的assert

test_example.py

def count_num(a: list) -> int:
    return len(a)
 
 
def test_count():
    assert count_num([1, 2, 3]) != 3

执行测试:

pytest test_example.py

执行结果:

C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest>pytest test_example.py -v
================================================================= test session starts =================================================================
platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- d:\coding\python3.6\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
plugins: Faker-8.11.0
collected 1 item                                                                                                                                       
 
test_example.py::test_count FAILED                                                                                                               [100%]
 
====================================================================== FAILURES =======================================================================
_____________________________________________________________________ test_count ______________________________________________________________________
 
    def test_count():
>       assert count_num([1, 2, 3]) != 3
E       assert 3 != 3
E        +  where 3 = count_num([1, 2, 3])
 
test_example.py:11: AssertionError
=============================================================== short test summary info ===============================================================
FAILED test_example.py::test_count - assert 3 != 3
================================================================== 1 failed in 0.16s ==================================================================

备注:

  • .代表测试通过,F代表测试失败;
  • -v显示详细的测试信息, -h显示pytest命令详细的帮助信息;

标记

默认情况下,pytest会在当前目录下寻找以test_为开头(以_test结尾)的测试文件,并且执行文件内所有以test_为开头(以_test为结尾)的所有函数和方法;
  1. 指定运行测试用例,可以通过::显示标记(文件名::类名::方法名)(文件名::函数名)
pytest test_example3.py::test_odd
  1. 指定一些测试用例测试运行,可以使用-k模糊匹配
pytest -k example
  1. 通过pytest.mark.skip()或者pytest.makr.skipif()条件表达式,跳过指定的测试用例
import pytest
 
test_flag = False
 
@pytest.mark.skip()
def test_odd():
    num = random.randint(0, 100)
    assert num % 2 == 1
 
 
@pytest.mark.skipif(test_flag is False, reason="test_flag is False")
def test_even():
    num = random.randint(0, 1000)
    assert num % 2 == 0
  1. 通过pytest.raises()捕获测试用例可能抛出的异常
def test_zero():
    num = 0
    with pytest.raises(ZeroDivisionError) as e:
        num = 1/0
    exc_msg = e.value.args[0]
    print(exc_msg)
    assert num == 0
  1. 预先知道测试用例会失败,但是不想跳过,需要显示提示信息,使用pytest.mark.xfail()
@pytest.mark.xfail()
def test_sum():
    random_list = [random.randint(0, 100)  for x in range(10)]
    num = sum(random_list)
    assert num < 20
  1. 对测试用例进行多组数据测试,每组参数都能够独立执行一次(可以避免测试用例内部执行单组数据测试不通过后停止测试)
@pytest.mark.parametrize('num,num2', [(1,2),(3,4)])
def test_many_odd(num: int, num2: int):
    assert num % 2 == 1
    assert num2 % 2 == 0

固件(Fixture)

固件就是一些预处理的函数,pytest会在执行测试函数前(或者执行后)加载运行这些固件,常见的应用场景就有数据库的连接和关闭(设备连接和关闭)

简单使用

import pytest
 
 
@pytest.fixture()
def postcode():
    return "hello"
 
 
def test_count(postcode):
    assert postcode == "hello"
按照官方的解释就是当运行测试函数,会首先检测运行函数的参数,搜索与参数同名的fixture,一旦pytest找到,就会运行这些固件,获取这些固件的返回值(如果有),并将这些返回值作为参数传递给测试函数;

预处理和后处理

接下来进一步验证关于官方的说法:

import pytest
 
 
@pytest.fixture()
def connect_db():
    print("Connect Database in .......")
    yield
    print("Close Database out .......")
 
 
def read_database(key: str):
    p_info = {
        "name": "zhangsan",
        "address": "China Guangzhou",
        "age": 99
    }
    return p_info[key]
 
 
def test_count(connect_db):
    assert read_database("name") == "zhangsan"

执行测试函数结果:

============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Coding\Python3.6\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
plugins: Faker-8.11.0
collecting ... collected 1 item
 
test_example.py::test_count Connect Database in .......
PASSED                                       [100%]Close Database out .......
 
 
============================== 1 passed in 0.07s ==============================

备注:

  • 首先从结果上看验证了官方的解释,pytest执行测试函数前会寻找同名的固件加载运行;
  • connect_db固件中有yield,这里pytest默认会判断yield关键词之前的代码属于预处理,会在测试前执行,yield之后的代码则是属于后处理,将在测试后执行;

作用域
从前面大致了解了固件的作用,抽离出一些重复的工作方便复用,同时pytest框架中为了更加精细化控制固件,会使用作用域来进行指定固件的使用范围,(比如在这一模块中的测试函数执行一次即可,不需要模块中的函数重复执行)更加具体的例子就是数据库的连接,这一连接的操作可能是耗时的,我只需要在这一模块的测试函数运行一次即可,不需要每次都运行。

而定义固件是,一般通过scop参数来声明作用,常用的有:

function: 函数级,每个测试函数都会执行一次固件;
class: 类级别,每个测试类执行一次,所有方法都可以使用;
module: 模块级,每个模块执行一次,模块内函数和方法都可使用;
session: 会话级,一次测试只执行一次,所有被找到的函数和方法都可用。

import pytest
 
 
@pytest.fixture(scope="function")
def func_scope():
    print("func_scope")
 
 
@pytest.fixture(scope="module")
def mod_scope():
    print("mod_scope")
 
 
@pytest.fixture(scope="session")
def sess_scope():
    print("session_scope")
 
 
def test_scope(sess_scope, mod_scope, func_scope):
    pass
 
 
def test_scope2(sess_scope, mod_scope, func_scope):
    pass

执行结果:

============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Coding\Python3.6\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
plugins: Faker-8.11.0
collecting ... collected 2 items
 
test_example2.py::test_scope session_scope
mod_scope
func_scope
PASSED                                      [ 50%]
test_example2.py::test_scope2 func_scope
PASSED                                     [100%]
 
============================== 2 passed in 0.07s ==============================

从这里可以看出module,session作用域的固件只执行了一次,可以验证官方的使用介绍

自动执行

有人可能会说,这样子怎么那么麻烦,unittest框架中直接定义setUp就能自动执行预处理,同样的pytest框架也有类似的自动执行; pytest框架中固件一般通过参数autouse控制自动运行。
import pytest
 
 
@pytest.fixture(scope='session', autouse=True)
def connect_db():
   print("Connect Database in .......")
   yield
   print("Close Database out .......")
 
 
def test1():
   print("test1")
 
 
def test2():
   print("test")

执行结果:

============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Coding\Python3.6\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
plugins: Faker-8.11.0
collecting ... collected 2 items
 
test_example.py::test1 Connect Database in .......
PASSED                                            [ 50%]test1
 
test_example.py::test2 PASSED                                            [100%]test
Close Database out .......
 
 
============================== 2 passed in 0.07s ==============================

从结果看到,测试函数运行前后自动执行了connect_db固件;

参数化

前面简单的提到过了@pytest.mark.parametrize通过参数化测试,而关于固件传入参数时则需要通过pytest框架中内置的固件request,并且通过request.param获取参数

import pytest
 
 
@pytest.fixture(params=[
    ('redis', '6379'),
    ('elasticsearch', '9200')
])
def param(request):
    return request.param
 
 
@pytest.fixture(autouse=True)
def db(param):
    print('\nSucceed to connect %s:%s' % param)
 
    yield
 
    print('\nSucceed to close %s:%s' % param)
 
 
def test_api():
    assert 1 == 1

执行结果:

============================= test session starts =============================
platform win32 -- Python 3.6.8, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 -- D:\Coding\Python3.6\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\libuliduobuqiuqiu\Desktop\GitProjects\PythonDemo\pytest
plugins: Faker-8.11.0
collecting ... collected 2 items
 
test_example.py::test_api[param0] 
Succeed to connect redis:6379
PASSED                                 [ 50%]
Succeed to close redis:6379
 
test_example.py::test_api[param1] 
Succeed to connect elasticsearch:9200
PASSED                                 [100%]
Succeed to close elasticsearch:9200
 
 
============================== 2 passed in 0.07s ==============================

这里模拟连接redis和elasticsearch,加载固件自动执行连接然后执行测试函数再断开连接。

总结

对于开发来说为什么也要学习自动化测试这一块,很重要的一点就是通过自动化测试节省一些重复工作的时间,同时对于优化代码结构,提高代码覆盖率,以及后续项目重构都是有着很重要的意义,同时理解pytest和unittest在基础上有何区别有助于不同的业务场景中选择适合自己的测试工具。
这篇文章只是简单的介绍了pytest的基本使用,有兴趣的可以去看看官方文档,官方文档中还提到了如内置固件的使用,常用测试的场景等等。

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

在这里插入图片描述

软件测试面试小程序

被百万人刷爆的软件测试题库!!!谁用谁知道!!!全网最全面试刷题小程序,手机就可以刷题,地铁上公交上,卷起来!

涵盖以下这些面试题板块:

1、软件测试基础理论 ,2、web,app,接口功能测试 ,3、网络 ,4、数据库 ,5、linux

6、web,app,接口自动化 ,7、性能测试 ,8、编程基础,9、hr面试题 ,10、开放性测试题,11、安全测试,12、计算机基础

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/890747.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python Django 模型概述与应用

今天来为大家介绍 Django 框架的模型部分&#xff0c;模型是真实数据的简单明确的描述&#xff0c;它包含了储存的数据所必要的字段和行为&#xff0c;Django 遵循 DRY Principle 。它的目标是你只需要定义数据模型&#xff0c;然后其它的杂七杂八代码你都不用关心&#xff0c;…

龙迅LT9711 2PORT MIPI或者LVDS转TYPE-C

LT9711 1.描述&#xff1a; Lontium LT9711是双端口MIPI/LVDS到DP1.2转换器&#xff0c;内部有c型替代模式开关和PD控制器。MIPI DSI/CSI输入具有可配置的单端口或双端口&#xff0c;具有1个时钟通道&#xff0c;1个~4个数据通道&#xff0c;最大运行2Gbps/通道&#xff0c;可…

2023 年值得关注的 8 个最佳免费开发者工具

开发者工具对开发人员的重要性不言而喻&#xff0c;保持最新工具的更新可以显著提高你的工作效率并简化您的工作流程。随着技术的快速发展&#xff0c;新的开发工具不断被引入市场。今天&#xff0c;我们将分享 2023 年你值得关注的最新开发者工具。 1.Plaky Plaky 是一种基于…

JVM——JDK 监控和故障处理工具总结

文章目录 JDK 命令行工具jps:查看所有 Java 进程jstat: 监视虚拟机各种运行状态信息 jinfo: 实时地查看和调整虚拟机各项参数jmap:生成堆转储快照**jhat**: 分析 heapdump 文件**jstack** :生成虚拟机当前时刻的线程快照 JDK 可视化分析工具JConsole:Java 监视与管理控制台连接…

司徒理财:8.17黄金反弹遇阻,1900现价空!

黄金趋势下跌&#xff0c;现在反弹遇阻&#xff0c;继续空&#xff01;除非行情强势站上1907位置&#xff0c;否则还是空头下跌走势&#xff0c;反弹遇阻直接空&#xff01;      黄金从走势上看&#xff0c;一直阴跌&#xff0c;并且在昨日加速下行&#xff01;现在黄金受…

ubuntu18.04从0到1在ros上跑yolo5

ubuntu篇---ubuntu20.04安装cuda和cudnn_ubuntu安装cudann_心惠天意的博客-CSDN博客操作系统环境&#xff1a;Ubuntu 20.041. 安装N卡驱动首先我们需要添加源&#xff0c;sudo add-apt-repository ppa:graphics-drivers/ppasudo apt update然后检查可以安装的驱动版本&#xff…

华为将收取蜂窝物联网专利费,或将影响LPWAN市场发展

近日&#xff0c;华为正式公布了其4G和5G手机、Wi-Fi6设备和物联网产品的专利许可费率&#xff0c;其中包含了长距离通信技术蜂窝物联网。作为蜂窝物联网技术的先驱&#xff0c;华为是LTE Category NB (NB-IoT)、LTE Category M和其他4G物联网标准的主要贡献者。 在NB-IoT领域…

『论文精读』Data-efficient image Transformers(DeiT)论文解读

『论文精读』Data-efficient image Transformers(DeiT)论文解读 文章目录 一. DeiT简介二. 知识蒸馏(knowledge distillation)2.1. KLDivloss2.2. 蒸馏温度 τ \tau τ2.3. distillation in transformer 三. better hyperparameter四. data augmentation五. label smoothing参…

随机微分方程

应用随机过程|第7章 随机微分方程 见知乎&#xff1a;https://zhuanlan.zhihu.com/p/348366892?utm_sourceqq&utm_mediumsocial&utm_oi1315073218793488384

2023年4大收银系统软件排名(真实测评)

现在满大街的各种服装店、便利店、百货店、母婴店...... 每天都要处理大量的订单。 使用传统的人工开单记账&#xff0c;效率低下、客户体验差、而且容易出错&#xff0c;需要耗费很多时间来回对账&#xff1b; 聪明的零售店老板都已经开始使用收银系统软件&#xff0c;通过手…

线程同步条件变量

为何要线程同步 在线程互斥中外面解决了多线程访问共享资源所会造成的问题。 这篇文章主要是解决当多线程互斥后引发的新的问题&#xff1a;线程饥饿的问题。 什么是线程饥饿&#xff1f;互斥导致了多线程对临界区访问只能改变为串行&#xff0c;这样访问临界资源的代码只能…

手把手教你Element Plus前端导出Excel表格

目录 需求背景&#xff1a; 项目环境&#xff1a; 最终效果&#xff1a; 具体实现&#xff1a; 1、下载第三方依赖包&#xff1a; pnpm下载命令&#xff1a; npm下载命令&#xff1a; 2、查看是否下载成功&#xff1a; 3、引入需要使用的页面js中 4、编写导出表格函数…

【0基础入门Python笔记】一、python 之基础语法、基础数据类型、复合数据类型及基本操作

一、python 之基础语法、基础数据类型、复合数据类型及基本操作 基础语法规则基础数据类型数字类型&#xff08;Numbers&#xff09;字符串类型&#xff08;String&#xff09;布尔类型&#xff08;Boolean&#xff09; 复合数据类型List&#xff08;列表&#xff09;Tuple&…

【傅里叶级数与傅里叶变换】数学推导——2、[Part2:T = 2 π的周期函数的傅里叶级数展开] 及 [Part3:周期为2L的函数展开]

文章内容来自DR_CAN关于傅里叶变换的视频&#xff0c;本篇文章提供了一些基础知识点&#xff0c;比如三角函数常用的导数、三角函数换算公式等。 文章全部链接&#xff1a; 基础知识点 Part1&#xff1a;三角函数系的正交性 Part2&#xff1a;T2π的周期函数的傅里叶级数展开 P…

顺序程序设计

#include <iostream> #include <stdio.h>int main() {float f, c;f 64.0f;c (5.0 / 9) * (f - 32);printf("f%f \n \\c%f\n", f, c);return 0; }

poste邮件服务器搭建

关于poste poste是一款开源邮件服务软件&#xff0c;可以很方便的搭建&#xff1a;SMTP IMAP POP3 反垃圾邮件 防病毒 Web 管理 Web 电子邮件&#xff0c;支持以下特性。 SPF、DKIM、DMARC、SRS 的原生实现&#xff0c;带有简单的向导用于检测木马、病毒、恶意软件的防…

【Hyper-V】Windows11 家庭版怎么启用虚拟机Hyper-V

在电脑Windows11系统上启用虚拟机Hyper-V&#xff0c;打开 启用和关闭WIndows功能&#xff0c;找到其中一项Hyper-V&#xff0c;对于家庭版的系统用户来说&#xff0c;这个选项是没有的&#xff0c;接下来讲一讲怎么开启。 安装Hyper-V 创建一个文件名为Hyper-v.bat&#xff…

人工智能原理(9)

目录 一、人工神经元模型 1、概念 2、分类 二、感知器的结构 三、反向传播网络 四、自组织映射神经网络 五、离散HOPFIELD网络 1、离散Hopfield网络结构 2、离散Hopfield网络的稳定性 3、离散Hopfield网络学习算法 六、脉冲耦合神经网络 一、人工神经元模型 1、概念…

Centos7安装Docker及配置加速器地址

一、安装docker #1.yum 包更新到最新 yum update #2.安装需要的软件包&#xff0c;yum-util 提供yum-config-manager功能&#xff0c;另外两个是devicemapper驱动依赖的 yum install -y yum-utils device-mapper-persistent-data lvm2 #3.设置yum源 yum-config-manager --add…

【推荐】深入浅出学习Spring框架【上】

​ 目录 1.spring简介 1.1含义 1.2优点 2&#xff0c;Spring之IOC详解 2.1&#xff0c;控制反转是什么 2.2&#xff0c;控制反转案例 2.1.3案例前台测试 3、IoC的三种注入方式 3.1 构造方法注入 3.2 setter方法注入 3.3 接口注入&#xff08;自动装配&#xff09;用的最多&…