当前位置: 首页 > news >正文

软测入门(六)pytest单元测试

pytest

pytest是python的一种单元测试框架,同自带的unit test测试框架类似,但pytest更简洁高效。

单元测试:

  • 测试 函数、类、方法能不能正常运行
  • 测试的结果是否符合我们的预期结果

安装

pip install -U pytest

基本使用

  • 通过pytest包使用
import pytestdef test_a():print("test_a")return 1 + 0def test_b():print("test_b")return 1 / 0if __name__ == '__main__':pytest.main()

默认情况下:在main中直接使用pytest的main()方法,会把文件中所有test_*开头的方法执行一遍。

  • 通过终端的命令使用,到所在目录下执行
# pytest或加参数都可
pytest -s

单量执行测试文件

import pytestdef test_1():print("test_1+++")return 1 + 0def test_2():print("test_2--------")return 1 / 0if __name__ == '__main__':# 只运行 test_py2.py文件中的测试方法pytest.main(["-s", "test_py2.py"])

配置文件

测试自动触发规则:

  • 在测试目录中或当前的目录中寻找

  • 名称为 test_*.py*_test.py的文件

  • Test开头的类,且没有初始化__init__方法

  • 以上目录或类中,test开头的函数或方法

  • 会执行uinit test的测试用例类

运行pytest时,自动读取所在目录中的配置文件pytest.ini。在测试文件所在目录下创建一个pytest.ini

内容如下:注意:以下内容请将 中文全部删掉,否则可能出问题,这里只是为了解释配置的。

[pytest]
; ini文件中的英文分号,都是注释
addopts = -s   ;选项参数testpaths = ./   ;测试模块所在目录python_files = test_*.py *test.py  ;测试文件名称python_classes = Test_*  ;测试类名称规则python_functions = test_*  ;测试函数或者方法命名规则

假如我把python_functions修改为demo_*,那么只有以demo_函数名命名的函数才会被执行。

断言

import pytestdef test_1():print("test_1+++")assert 20 == 20def test_2():print("test_2--------")assert "a" in "hello"if __name__ == '__main__':pytest.main(["-s", "test_py2.py"])

标记

标记跳过测试

  • 标记跳过(装饰器)
  • 标记失败(装饰器)
@pytest.mark.skip("跳过")
def test_2():print("test_2--------")return 1 / 0@pytest.mark.xfail(raises=ZeroDivisionError)
def test_3():print("test_3--------")return 1 / 0

参数化

比如写了一个函数需要模拟一些参数进行调用,那么可以使用:

parametrize装饰器:

  • [“a”, “b”],列表中定义的方法参数名
  • [(1, 2), (2, 2), (50, 51)],三组测试数据,表示此方法会被调用3次
import pytest@pytest.mark.parametrize(["a", "b"], [(1, 2), (2, 2), (50, 51)])
def test_1(a, b):print("test_1+++++++")assert a + b > 100if __name__ == '__main__':pytest.main(["-s", "test_py3.py"])

夹具

在测试之前和之后执行,用于固定测试环境,及清理回收测试资源。

setup_...teardown_...

  • 模块的夹具:setup_module()和teardown_module(),在python文件加载前和文件内容结束后执行

    import pytestdef setup_module(args):print("setup_module", args)def teardown_module(args):print("teardown_module", args)def test_fun_a():print("------------", "test_fun_a")def test_fun_b():print("------------", "test_fun_b")class TestOne:def test_1(self):print("------", "test_1")def test_2(self):print("------", "test_2")if __name__ == '__main__':pytest.main(["-s", "test_py4.py"])###################################################结果########################
    test_py4.py setup_module <module 'test_py4' from 'D:\\environment\\python-workspace\\androidTest\\pytest\\test_py4.py'>
    ------------ test_fun_a
    .------------ test_fun_b
    .------ test_1
    .------ test_2
    .teardown_module <module 'test_py4' from 'D:\\environment\\python-workspace\\androidTest\\pytest\\test_py4.py'>
    
  • 函数的夹具:setup_function()和teardown_function(),py中函数执行前和执行后执行(注意是函数,不是类中的方法)

    import pytestdef setup_function(args):print("setup_function", args)def teardown_function(args):print("teardown_function", args)def test_fun_a():print("------------", "test_fun_a")def test_fun_b():print("------------", "test_fun_b")class TestOne:def test_1(self):print("------", "test_1")def test_2(self):print("------", "test_2")if __name__ == '__main__':pytest.main(["-s", "test_py4.py"])
    ###################################################结果########################test_py4.py setup_function <function test_fun_a at 0x000001ED1D8C31F8>
    ------------ test_fun_a
    .teardown_function <function test_fun_a at 0x000001ED1D8C31F8>
    setup_function <function test_fun_b at 0x000001ED1D8C3288>
    ------------ test_fun_b
    .teardown_function <function test_fun_b at 0x000001ED1D8C3288>
    ------ test_1
    .------ test_2
    
  • 类的夹具:setup_class()和teardown_class(),类被加载前和销毁后执行

    class TestOne:def setup_class(self):print("------", "setup___test_1")def teardown_class(self):print("------", "teardown___test_1")def test_1(self):print("------", "test_1")def test_2(self):print("------", "test_2")if __name__ == '__main__':pytest.main(["-s", "test_py4.py"])###################################################结果########################
    ------ setup___test_1
    ------ test_1
    .------ test_2
    .------ teardown___test_1
    
  • 方法的夹具:setup_method()和teardown_method(),类被加载前和销毁后执行

    class TestOne:def setup_class(self):print("------", "setup___test_1")def teardown_class(self):print("------", "teardown___test_1")def setup_method(self, args):print("------", "setup_methods___test_1", args)def teardown_method(self, args):print("------", "teardown_methods___test_1", args)def test_1(self):print("------", "test_1")def test_2(self):print("------", "test_2")if __name__ == '__main__':pytest.main(["-s", "test_py4.py"])###################################################结果########################
    setup___test_1
    ------ setup_methods___test_1 <bound method TestOne.test_1 of <test_py4.TestOne object at 0x000001D972FB28C8>>
    ------ test_1
    .------ teardown_methods___test_1 <bound method TestOne.test_1 of <test_py4.TestOne object at 0x000001D972FB28C8>>
    ------ setup_methods___test_1 <bound method TestOne.test_2 of <test_py4.TestOne object at 0x000001D972FB2988>>
    ------ test_2
    .------ teardown_methods___test_1 <bound method TestOne.test_2 of <test_py4.TestOne object at 0x000001D972FB2988>>
    ------ teardown___test_1

fixture装饰器夹具

import pytest# 设置夹具
@pytest.fixture()
def before():print("before")# 使用夹具
@pytest.mark.usefixtures("before")
def test_1():print("test_1执行")# 设置夹具 有返回值
@pytest.fixture()
def login():print("login")return "user"# 使用夹具 入参
def test_2(login):print("test_2执行")print(login)@pytest.fixture(params=[1, 2, 3])
def init_data(request):# params中有三个元素,那么此方法将执行三遍print("参数:", request.param)return request.paramdef test_data(init_data):assert init_data > 2if __name__ == '__main__':pytest.main(["-s", "test_py5.py"])
###################################################结果################################
test_py5.py 参数: 1
F参数: 2
F参数: 3
.before
test_1执行
.login
test_2执行
user================================== FAILURES ===================================
________________________________ test_data[1] _________________________________init_data = 1def test_data(init_data):
>       assert init_data > 2
E       assert 1 > 2test_py5.py:24: AssertionError
________________________________ test_data[2] _________________________________init_data = 2def test_data(init_data):
>       assert init_data > 2
E       assert 2 > 2test_py5.py:24: AssertionError
=========================== short test summary info ===========================
FAILED test_py5.py::test_data[1] - assert 1 > 2
FAILED test_py5.py::test_data[2] - assert 2 > 2
========================= 2 failed, 3 passed in 0.03s =========================

pytest插件

html报告

  • 安装插件

    pip install pytest-html
    
  • 使用

    • 命令行方式

      pytest --html=存储路径/report.html
      
    • 配置文件方式

      [pytest]
      addopts = -s --html=./report.html
      

指定运行顺序

  • 安装插件

    pip install pytest-ordering
    
  • 使用

    添加装饰器@pytest.mark.run(order=x)到测试函数或者方法上。

    优先级:

    • 0和正整数 > 没有标记 > 负整数标记
    • 且在各个阶段,数越小运行优先级越高
    import pytest@pytest.mark.run(order=0)
    def test_1():print("1")@pytest.mark.run(order=-3)
    def test_2():print("2")@pytest.mark.run(order=3)
    def test_3():print("3")@pytest.mark.run(order=2)
    def test_4():print("4")@pytest.mark.run(order=1)
    def test_5():print("5")if __name__ == '__main__':pytest.main(["-s", "test_py6.py"])###################################################结果###############################
    test_py6.py 1
    .5
    .4
    .3
    .2
    

失败重试

  • 安装插件

    pip install pytest-rerunfailures
    
  • 使用

    配置,--reruns 5 重试5次

    [pytest]
    addopts = -s --reruns 5
    

相关文章:

软测入门(六)pytest单元测试

pytest pytest是python的一种单元测试框架&#xff0c;同自带的unit test测试框架类似&#xff0c;但pytest更简洁高效。 单元测试&#xff1a; 测试 函数、类、方法能不能正常运行测试的结果是否符合我们的预期结果 安装 pip install -U pytest基本使用 通过pytest包使用…...

经典分类模型回顾5—DenseNet实现图像分类(matlab)

DenseNet&#xff0c;全称为Densely Connected Convolutional Networks&#xff0c;中文名为密集连接卷积网络&#xff0c;是由李沐等人在2017年提出的一种深度神经网络架构。 DenseNet旨在解决深度神经网络中的梯度消失问题和参数数量过多的问题&#xff0c;通过构建密集连接…...

基于flask+bootstrap+echarts+mysql的鱼村小馆订餐后台管理系统

&#x1f4cb; 个人简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是阿牛&#xff0c;全栈领域优质创作者。&#x1f61c;&#x1f4dd; 个人主页&#xff1a;馆主阿牛&#x1f525;&#x1f389; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4d…...

Spark使用Log4j将日志发送到Kafka

文章目录自定义KafkaAppender修改log4j.properties配置启动命令配置添加参数启动之后可以在Kafka中查询发送数据时区问题-自定义实现JSONLayout解决自定义JSONLayout.java一键应用可能遇到的异常ClassNotFoundException: xxx.KafkaLog4jAppenderUnexpected problem occured dur…...

c++类与对象整理(上)

目录 1.类的引入 2.类的定义 3.类的访问限定符及封装 1&#xff09;访问限定符 2&#xff09;封装 4.类的作用域 5.类的实例化 6.类的对象大小的计算 1&#xff09;类对象的存储方式 2&#xff09;内存对齐和大小计算 ​编辑 7.类成员函数的this指针 1&#xff09…...

Docker学习(十九)什么是镜像的元数据?

在 Docker 中&#xff0c;镜像的元数据是指与镜像相关的所有信息&#xff0c;包括镜像的名称和标签、作者、描述、创建日期、环境变量、命令等。这些信息都是通过 Dockerfile 或命令行创建和指定的。 镜像的元数据被存储在 Docker Registry 中&#xff0c;并在使用 docker pull…...

Python如何获取弹幕?给你介绍两种方式

前言 弹幕可以给观众一种“实时互动”的错觉&#xff0c;虽然不同弹幕的发送时间有所区别&#xff0c;但是其只会在视频中特定的一个时间点出现&#xff0c;因此在相同时刻发送的弹幕基本上也具有相同的主题&#xff0c;在参与评论时就会有与其他观众同时评论的错觉。 在国内…...

JAVA- AOP 面向切面编程 Aspect切面工具类 记录特定方法执行时的入参、执行时间、返参等内容

背景&#xff1a;JAVA项目&#xff0c;使用AOP对指定函数进行切面。能够记录特定方法执行时的入参、执行时间、返参结果等内容。 文章目录1、自定义注解类1.1 Target1.2 Retention2、Aspect切面工具2.1 JointPoint2.2 Pointcut2.3 切面中的相关注解3、同一个类里调用AOP4、其他…...

「史上最全的 TCG 规范解读」TCG 规范架构概述(下)

可信计算组织&#xff08;Ttrusted Computing Group,TCG&#xff09;是一个非盈利的工业标准组织&#xff0c;它的宗旨是加强不同计算机平台上计算环境的安全性。TCG 于 2003 年春成立&#xff0c;并采纳了由可信计算平台联盟&#xff08;the Trusted Computing Platform Allia…...

GDScript 导出变量 (4.0)

概述 导出变量的功能在3.x版本中也是有的&#xff0c;但是4.0版本对其进行了语法上的改进。 导出变量在日常的游戏制作中提供节点的自定义参数化调节功能时非常有用&#xff0c;除此之外还用于自定义资源。 本文是&#xff08;Bilibili巽星石&#xff09;在4.0官方文档《GDScr…...

JAVA知识点全面总结6:泛型反射和注解

六.JAVA知识点全面总结6泛型反射和注解 1.什么是泛型?可以用在哪里&#xff1f; 2.泛型擦除机制是什么&#xff1f;为什么擦除&#xff1f; 3.通配符是什么&#xff1f;作用是什么&#xff1f; 未更新 1.注解是什么&#xff1f;有什么用&#xff1f; 2.注解的自定义和实…...

死代码删除(DCE,Dead Code Elimination)和激进的死代码删除(ADCE,Aggressive DCE)

死代码删除&#xff08;DCE&#xff0c;Dead Code Elimination&#xff09;和激进的死代码删除&#xff08;ADCE&#xff0c;Aggressive DCE&#xff09;死代码删除&#xff08;DCE&#xff0c;Dead Code Elimination&#xff09;DCE简介DCE基本算法激进的死代码删除&#xff0…...

询问new bing关于android开发的15个问题(前景、未来、发展方向)

前言&#xff1a;new bing是基于chat-gpt的新搜索工具&#xff0c;可以采用对话方式进行问题搜索&#xff0c;经过排队等候终于可以使用new bing&#xff0c;询问了目前我最关心的关于android开发几个问题 文章目录1.如何学好android开发&#xff1f;2.android开发能做什么?3.…...

【C++】初识类和对象

&#x1f3d6;️作者&#xff1a;malloc不出对象 ⛺专栏&#xff1a;C的学习之路 &#x1f466;个人简介&#xff1a;一名双非本科院校大二在读的科班编程菜鸟&#xff0c;努力编程只为赶上各位大佬的步伐&#x1f648;&#x1f648; 目录前言一、面向过程和面向对象初步认识二…...

EPICS S7nodave手册

第一章&#xff1a;介绍 本手册分为6章(不算次介绍部分)。第一章介绍s7nodave用于EPICS的设备支持的概念和特新。第二章描述启动一个使用s7nodave的IOC项目所需要的几步。第三章描述s7nodave支持的IOC shell命令。之后&#xff0c;第四章解释s7nodave支持的各种记录类型。最后…...

2023最新版本RabbitMQ的持久化和简单使用

上节讲了 RabbitMQ下载安装教程 &#xff0c; 本节主要介绍RabbitMQ的持久化和简单使用。 一、RabbitMQ消息持久化 当处理一个比较耗时得任务的时候&#xff0c;也许想知道消费者&#xff08;consumers&#xff09;是否运行到一半就挂掉。在当前的代码中&#xff0c;当RabbitM…...

函数式编程

函数式编程&#xff08;一&#xff09; 文章目录函数式编程&#xff08;一&#xff09;1. 前言1.1 概念2. Lambda 表达式2.1 概述2.2 基本的格式2.3 触发条件2.4 Lambda表达式2.4.1 无参无返回值2.4.2 有参无返回值2.4.3 无参数有返回值2.4.4 有参有返回值【重点】2.4.4.1 比较…...

【Java 类】001-访问修饰符、命名规范

【Java 类】001-访问修饰符、命名规范 文章目录【Java 类】001-访问修饰符、命名规范一、访问修饰符概述1、是什么2、作用作用问题3、访问修饰符有哪些4、作用对象二、访问修饰符使用演示1、类访问修饰符演示第一步&#xff1a;创建 Dog 类&#xff1a;public第二步&#xff1a…...

【C++】命名空间

&#x1f3d6;️作者&#xff1a;malloc不出对象 ⛺专栏&#xff1a;C的学习之路 &#x1f466;个人简介&#xff1a;一名双非本科院校大二在读的科班编程菜鸟&#xff0c;努力编程只为赶上各位大佬的步伐&#x1f648;&#x1f648; 目录前言一、命名空间产生的背景二、命名空…...

【AutoSAR】【MCAL】Dio

一、结构 二、功能介绍 DIO&#xff08;数字输入输出&#xff09;驱动模块主要是对端口&#xff08;Port&#xff09;&#xff0c;通道&#xff08;Channel&#xff09;和通道组&#xff08;ChannelGroup&#xff09;进行读写操作。 通道&#xff08;Channel&#xff09;&…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

ESP32读取DHT11温湿度数据

芯片&#xff1a;ESP32 环境&#xff1a;Arduino 一、安装DHT11传感器库 红框的库&#xff0c;别安装错了 二、代码 注意&#xff0c;DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

华为OD机试-最短木板长度-二分法(A卷,100分)

此题是一个最大化最小值的典型例题&#xff0c; 因为搜索范围是有界的&#xff0c;上界最大木板长度补充的全部木料长度&#xff0c;下界最小木板长度&#xff1b; 即left0,right10^6; 我们可以设置一个候选值x(mid)&#xff0c;将木板的长度全部都补充到x&#xff0c;如果成功…...

【Linux】Linux安装并配置RabbitMQ

目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的&#xff0c;需要先安…...