字节8年经验之谈 —— 详解python自动化单元测试!

1. 前言

说实话,除了测试要求,我实在不知道写单元测试有什么意义,一个函数50行代码,有多种参数组合,为了测试这些条件,需要编写测试用例,写完的测试用例比需要测试的函数还长。也就是说,除了写函数,还要写测试用例,增加的工作量不是一点点。特别是,需求经常变化,维护功能性代码本身就需要很大的工作量,还怎么记得要同步更新测试用例呢?很多程序员连基本的注释都做不好,还谈什么单元测试。

我不喜欢测试用例的另外一个原因,就是我们目前的代码习惯是,除了基本的函数文档外,还会在函数文档中写上一些测试用的数据,这些数据既是写代码时候的测试数据,也算是就针对这些数据写代码吧。

相比之下,我们的文档和注释已经很好了,有些人会说,良好的命名和代码结构就能说明函数功能。我想说的是,啊呸,除了简单到不行的功能,否则永远是看注释来的方便,注释一行字,说明了业务功能和处理逻辑,而看代码需要10行,还需要花心思理解其中的逻辑运算。为什么那么多人喜欢造轮子,就是看不懂逻辑,但是知道要干什么,没办法,自己搞一套咯。

但是项目有要求,要有单元测试。没办法,请教测试组的同时有没有办法可以自动生成单元测试,得到的回答是,你好懒啊

2. 原理

用python的同学都是到函数文档的个什么东西,没错,我的想法就是在函数文档中写单元测试,另外用脚本提取函数文档,生成单元测试文件,岂不快哉。

# -*- coding: utf-8 -*-
"""
python模块的第一个注释,就是模块文档,比如这一行
"""def other_func(a,b):"""函数的第一个注释,就是函数文档,比如这一行,当然也可以是多行"""passclass maths():"""类的第一个注释,就是类文档,比如这一行"""def __init__(self):passdef add(self, a,b):"""类方法的第一个注释,就是类方法的文档,比如这一行"""pass
现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。
如果你不想再体验自学时找不到资源,没人解答问题,坚持几天便放弃的感受
可以加入我们一起交流。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛
分享他们的经验,还会分享很多直播讲座和技术沙龙
可以免费学习!划重点!开源的!!!
qq群号:691998057【暗号:csdn999】

3. 单元测试的简单类型

单元测试的简单类型,包含以下几个: - 测试一个简单函数,没有外部依赖 - 测试一个简单函数,包含外部函数依赖 - 测试一个简单函数,包含外部类依赖 - 测试一个类方法,包含外部函数依赖 - 测试一个类方法,包含外部类依赖

为什么特别说明包含外部依赖呢?因为我们写代码的时候,外部接口依赖说不定还没有开始开发呢,而且开发了也不一定正确对吧,此时我们需要假设外部依赖已经完成并且是正确的,它会返回我们预期的值,这样我们就可以接着往下写代码了。

这个假设,就是 mock,很有意思的东西。为什么简单说明,请看下面的示例,我们需要调用外部http接口,但是http接口没有完成,此时就假设它已经完成,并且返回值是10:

def get_http(url):return request(url)   # 正常的代码,返回request的值
#--->
def get_http(url):return 10             # 测试时候,我们假设它返回10

在正式代码中肯定是写 request(url),但是在单元测试的代码中,我们可以使用mock使它返回10.

@mock.patch('request')
def get_http(mock_request):mock_request.return_value = 10return request(url)    # 此时返回值是10,因为我们用mock做了替换

4. 一个简单的例子

下面的一段代码是单元测试写法,包含了mock函数和mock类方法:

import unittest
from unittest import mockfrom unittest.pyauto_unittest_test import maths, func_add  # 导入需要测试的函数和类class Test_pyauto_unittest_test(unittest.TestCase):def setUp(self):passdef tearDown(self):pass# 测试一个类的方法,没有外部依赖def test_maths_add_0(self ,):a,b=1,2my_math = maths()result = my_math.add(a,b)self.assertEqual(result, 3)# 测试一个类的方法,并假设 self.add 的返回值是10def test_maths_add2_0(self ,):a,b=1,2my_math = maths()maths.add = mock.Mock(return_value = 10)  # 假设 self.add 的返回值是10result = my_math.add2(a,b)self.assertEqual(result, 10)# 测试一个类的方法,并假设调用外部函数的返回值是 10# 假设内部调用的类方法的返回值也是10 @mock.patch('unittest.pyauto_unittest_test.other_func')def test_maths_mul_0(self , mock_other_func):mock_other_func.return_value = 10   # 假设外部调用函数返回值是10 a,b=1,2my_math = maths()maths.add = mock.Mock(return_value = 10)  # 假设内部调用的类方法也是10result = my_math.mul(a,b)self.assertEqual(result, 20)# 测试一个函数,并假设内部调用的func_mul函数的返回值是10@mock.patch('unittest.pyauto_unittest_test.func_mul')def test_func_add_0(self , mock_func_mul):mock_func_mul.return_value = 10  # 假设内部调用的函数返回值是10a,b=1,2result = func_add(a,b)self.assertEqual(result, 20)if __name__ == '__main__':unittest.main()

看到没,这就是简单的单元测试的写法,已经涵盖了大部分测试用例写法。我们的目标,就是自动生成这样的测试用例。

既然都是模板套出来的,就很简单了。

5. 函数文档格式要求

既然是要自动生成代码,就需要事先约定格式要求,我们约定函数文档如下:

class maths():def __init__(self):passdef add(self, a,b):"""# 测试用例代码需要夹在 两个 === unittest === 之间=== unittest ===   a,b=1,2                         # 一些初始化参数mock.Mock maths.add=10          # mock 类的方法,可以是外部调用的类mock.patch other_func=10        # mock 一个函数my_math = maths()               # 实例化当前类input = my_math.add(a,b)        # 输入,即要测试的方法output = 3                      # 输出,要进行assertEqual的值=== unittest ===other unittest                  # 如果有多个测试,接着往下添加即可=== unittest ==="""return a+b

不管是测试函数还是测试类的方法啊,都以上面的格式约定规范化,是不是很简答啊。 我们就根据这些文档内容生成上面的测试用例,只要一一对应即可。

6. 生成测试用例

经过上面的讲解说明,接下来要做的事情就很简答了,包括遍历整个项目的每一个python文件,遍历每个模块的函数和类方法,提取函数文档,解析文档内容,依照格式生成对应的测试用例文件即可。

下面是配套资料,对于做【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!

最后: 可以在公众号:程序员小濠 ! 免费领取一份216页软件测试工程师面试宝典文档资料。以及相对应的视频学习教程免费分享!,其中包括了有基础知识、Linux必备、Shell、互联网程序原理、Mysql数据库、抓包工具专题、接口测试工具、测试进阶-Python编程、Web自动化测试、APP自动化测试、接口自动化测试、测试高级持续集成、测试架构开发测试框架、性能测试、安全测试等。

如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “点赞” “评论” “收藏” 一键三连哦!

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

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

相关文章

14-树-二叉树的最小深度

这是树的第14篇算法,力扣链接。 给定一个二叉树,找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明:叶子节点是指没有子节点的节点。 示例 1: 输入:root [3,9,20,null,null,15,7] 输出…

ubuntu18.04运行DynaSLAM,实例分割+多视图几何+背景修复

博主电脑上之前就安装了ORB-SLAM2所需的环境,所以baseline为ORB-SLAM2的算法几乎都是直接./build.sh即可。需要我们安装的内容就是python的环境,Pytorch或者TensorFlow,以及下载预训练模型和数据集。 一、安装ORB-SLAM2所需的库 C11 or C0x…

全网Bento和3D?点评2024年UX/UI设计趋势

2024年已经到来,对于UX/UI设计领域来说,这可能是过去若干年来UI / UX趋势最统一、最确定的一年。在接下来的文章中,笔者将在点评各个设计趋势的同时,分析现象背后的原因,并给新入行的设计师一些成长的建议。 什么是UI和…

数据结构-邻接矩阵

介绍 邻接矩阵,是表示图的一种常见方式,具体表现为一个记录了各顶点连接情况的呈正方形的矩阵。 假设一共有以下顶点,其连接关系如图所示 那么,怎么表示它们之间的连接关系呢? 我们发现,各条边所连接的都…

C语言题目:一些简单的编程和递归题目

以下的题目的较难的点都在注释里面讲解清楚了 一. 1.喝汽水,1瓶汽水1元,2个空瓶可以换一瓶汽水,给20元,可以喝多少汽水(编程实现)。 代码实现: int main() {int money 20;int price 1;int e…

C#,二进制数的非0位数统计(Bits Count)的算法与源代码

计算一个十进制数的二进制表示有多少位1? 1 遍历法(递归或非递归) 使用循环按位统计1的个数。 2 哈希查表法 利用一个数组或哈希生成一张表,存储不同二进制编码对应的值为1的二进制位数,那么在使用时,只…

(每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第10章 项目进度管理(五)

博主2023年11月通过了信息系统项目管理的考试,考试过程中发现考试的内容全部是教材中的内容,非常符合我学习的思路,因此博主想通过该平台把自己学习过程中的经验和教材博主认为重要的知识点分享给大家,希望更多的人能够通过考试&a…

控制程序执行流程

资源 资源下载 【免费】突破密码认证程序(修改函数返回地址)资源-CSDN文库 资源内容 源码 在上一篇文章里 修改函数返回地址-CSDN博客 流程 对程序进行编译 思路 了解栈的情况(函数地址、缓冲区偏移量)程序中密码认证的地…

SHERlocked93 的 2023 年终总结

工作之后感觉一年一年过的太快,没有个记录连回忆都无从回忆起,之前的年终总结: SHERlocked93 的 2022 年终总结SHERlocked93 的 2021 年终总结SHERlocked93 的 2020 年终总结SHERlocked93 的 2019 年终总结SHERlocked93 的 2018 年终总结SHER…

js设计模式:发布订阅模式

作用: 也称之为消息队列模式,或者pubsub模式 发布者发布消息(也可以理解为调用某函数),订阅者会收到消息,并且发布者可以将一些参数传递给订阅者。 是一种常用的参数传递方法,经典的pubsub.js,vue2中的$bus等都是用的这种模式。 示例: <!DOCTYPE html> <html lan…

模仿 STM32 驱动开发格式实验

1.模仿 STM32 寄存器定义 为了开发方便&#xff0c; ST 官方为 STM32F103 编写了一个叫做 stm32f10x.h 的文件&#xff0c;在这个文件 里面定义了 STM32F103 所有外设寄存器&#xff0c;我们可以使用其定义的寄存器来进行开发&#xff0c;比如我 们可以用如下代码来初始…

kube-ovn默认vpc

下面图是kube-ovn默认vpc的拓扑 默认vpc kube-ovn安装完成后会自带一个默认vpc是ovn-cluster&#xff0c;并且会在这个默认vpc下创建ovn-default子网、join子网&#xff0c; 默认子网 ovn-default是ovn-cluster下的默认子网&#xff0c;在创建pod时没有指定子网时会使用这个…

Python编程中的异常处理

什么是异常&#xff1f; 程序错误&#xff08;errors&#xff09;有时也被称为程序异常&#xff08;exceptions&#xff09;&#xff0c;这是每个编程人员都会经常遇到的问题。在过去&#xff0c;当遇到这类情况时&#xff0c;程序会终止执行并显示错误信息&#xff0c;通常是…

JAVA之Java线程核心详解

Java线程核心 1.进程和线程 进程&#xff1a;进程的本质是一个正在执行的程序&#xff0c;程序运行时系统会创建一个进程&#xff0c;并且给每个进程分配独立的内存地址空间保证每个进程地址不会相互干扰。同时&#xff0c;在 CPU 对进程做时间片的切换时&#xff0c;保证进程…

微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用

&#x1f3f7;️个人主页&#xff1a;鼠鼠我捏&#xff0c;要死了捏的主页 &#x1f3f7;️系列专栏&#xff1a;Golang全栈-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&…

猫头虎博客分享:深入解析 Visual Studio Code 1.86 版本新特性

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

测试文章笔记-SQL3种优化方法

SQL语句优化&#xff1a; 本质&#xff1a;降低执行时间 **核心思路&#xff1a;**找到执行计划中开销较高的操作&#xff0c;改写SQL语句或改变表访问方式调整执行计划。 举例&#xff1a; 1.使用索引替代全表扫描&#xff08;索引&#xff1a;是帮助MysQL高效获取数据的数…

【JVM】打破双亲委派机制

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;JVM ⛺️稳中求进&#xff0c;晒太阳 打破双亲委派机制 打破双亲委派机制三种方法 自定义类加载器 ClassLoader包含了四个核心方法 //由类加载器子类实现&#xff0c;获取二进制数据调用…

MySQL之json数据操作

1 MySQL之JSON数据 总所周知&#xff0c;mysql5.7以上提供了一种新的字段格式json&#xff0c;大概是mysql想把非关系型和关系型数据库一口通吃&#xff0c;所以推出了这种非常好用的格式&#xff0c;这样&#xff0c;我们的很多基于mongoDB的业务都可以用mysql去实现了。当然…

NumPy模块完结篇:深入探讨和高效利用【第85篇—NumPy模块】

NumPy模块完结篇&#xff1a;深入探讨和高效利用 NumPy是Python中用于科学计算的核心库之一&#xff0c;提供了高性能的多维数组对象&#xff08;numpy.ndarray&#xff09;以及许多用于操作这些数组的函数。在前面的几篇博客中&#xff0c;我们介绍了NumPy的基础知识、数组操…