当前位置: 首页 > 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;&…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

rknn优化教程(二)

文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK&#xff0c;开始写第二篇的内容了。这篇博客主要能写一下&#xff1a; 如何给一些三方库按照xmake方式进行封装&#xff0c;供调用如何按…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

Python如何给视频添加音频和字幕

在Python中&#xff0c;给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加&#xff0c;包括必要的代码示例和详细解释。 环境准备 在开始之前&#xff0c;需要安装以下Python库&#xff1a;…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

HDFS分布式存储 zookeeper

hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架&#xff0c;允许使用简单的变成模型跨计算机对大型集群进行分布式处理&#xff08;1.海量的数据存储 2.海量数据的计算&#xff09;Hadoop核心组件 hdfs&#xff08;分布式文件存储系统&#xff09;&a…...