Python 基础:使用 unittest 模块进行代码测试

目录

  • 一、测试函数
    • 2.1 通过案例
    • 2.2 不通过案例
    • 2.3 添加新测试
  • 二、测试类
    • 2.1 单个测试案例
    • 2.2 多个测试案例
  • 三、总结

遇到看不明白的地方,欢迎在评论中留言呐,一起讨论,一起进步!
在这里插入图片描述
本文参考:《Python编程:从入门到实践(第2版)》

一、测试函数

首先我们准备一个要测试的函数,这个函数在名和姓之间加上一个空格并将其首字母大写,再返回结果。

"""文件名:name_function"""
def get_formatted_name(first,last):"""生成整洁的姓名。"""full_name = f"{first} {last}"return full_name.title()

我们再来编写一个使用该函数的程序:

from name_function import get_formatted_nameprint("Enter 'q' at any time to quit.")
while True:first = input("\nPlease give me a first name:")if first == 'q':breaklast = input("Please give me a last name:")if last == 'q':breakformatted_name = get_formatted_name(first,last)print(f"\tNeatly formatted name:{formatted_name}.")

运行结果如下:
在这里插入图片描述

Python 标准库中的模块 unittest 提供了代码测试工具。 单元测试用于核实函数的某个方面没有问题。这样一来我们就不用自己编写程序依次运行了。

测试用例是一组单元测试,它们用来核实函数在各种情形下的行为是否都符合要求。

要进行单元测试,可先导入模块 unittest要测试的函数,再创建一个继承 unittest.TestCase 的类,并编写一系列方法对函数行为的不同方面进行测试。

2.1 通过案例

下面的测试用例只包含一个方法,它检查函数 get_formatted_name() 在给定名和姓时能否正确工作:

import unittest
from name_function import get_formatted_nameclass NamesTestCase(unittest.TestCase):"""测试name_function.py。"""def test_first_last_name(self):"""能够正确地处理像Janis Joplin这样的姓名吗?"""formatted_name = get_formatted_name('janis','joplin')self.assertEqual(formatted_name,'Janis Joplin')if __name__ == '__main__':unittest.main()

在运行这段程序时,所有以 test_ 打头的方法都将自动运行,这里 test_first_last_name 将自动执行。

在函数 test_first_last_name 中,使用了 unittest 类最有用的功能之一:断言方法,用来核实得到的结果是否与期望的结果一致。

这里我们将介绍 6 种常用地断言方法。
注:只能在继承 unittest.TestCas 的类中使用这些方法

方法用途
assertEqual(a,b)核实 a == b
assertNotEqual(a,b)核实 a != b
assertTrue(x)核实 x == True
assertFalse(x)核实 x == False
assertIn(item,list)核实 item 在 list 中
assertNotIn(item,list)核实 item 不在 list 中

if 代码块检查特殊变量 __name__,这个变量是在程序执行时设置的。
如果这个文件作为主程序执行,变量 __name__ 将被设置为__main__,此时调用 unittest.main() 来运行测试用例。
如果这个文件被测试框架导入,变量 __name__ 的值将不是__main__,则不会调用 unittest.main()

运行这段程序结果如下:
在这里插入图片描述
最后的 OK 表明该测试用例中的所有单元测试都通过了。

2.2 不通过案例

下面我们对被测试的函数进行修改,用于处理有中间名的格式:

def get_formatted_name(first,middle,last):"""生成整洁的姓名。"""full_name = f"{first} {middle} {last}"return full_name.title()

我们仍然使用原来的测试用例,让它检查函数 get_formatted_name() 在给定名和姓时能否正确工作,最后运行结果如下:
在这里插入图片描述
这里我们可以清楚地看到发生了几处错误,错误具体在哪里发生。


要将中间名设置为可选的,可在函数定义中将形参 middle 移到形参列表末尾,并将其默认值指定为一个空字符串。还需要添加一个 if 测试,以便根据是否提供了中间名相应地创建姓名:

def get_formatted_name(first,last,middle=''):"""生成整洁的姓名。"""if middle:full_name = f"{first} {middle} {last}"else:full_name = f"{first} {last}"return full_name.title()

我们再来运行测试用例,最后运行结果如下:
在这里插入图片描述
现在,测试用例通过了。这意味着这个函数又能正确处理像 Janis Joplin 这样的姓名了,而且我们无须手工测试这个函数。 这个函数之所以很容易修复,是因为未通过的测试让我们得知新代码破坏了函数原来的行为。

2.3 添加新测试

下面我们再编写一个测试,用于测试包含中间名的姓名。为此,在 NamesTestCase 类中再添加一个方法:

import unittest
from name_function import get_formatted_nameclass NamesTestCase(unittest.TestCase):"""测试name_function.py。"""def test_first_last_name(self):"""能够正确地处理像Janis Joplin这样的姓名吗?"""formatted_name = get_formatted_name('janis','joplin')self.assertEqual(formatted_name,'Janis Joplin')def test_first_last_middle_name(self):  # 这里我们先添加了一个测试"""能够正确地处理像Wolfgang Amadeus Mozart这样的姓名吗?"""formatted_name = get_formatted_name('wolfgang', 'mozart', 'amadeus')self.assertEqual(formatted_name, 'Wolfgang Amadeus Mozart')if __name__ == '__main__':unittest.main()

注意:测试方法名必须以 test_ 打头,这样它才会在我们运行时自动运行。

再次运行一下,两个测试都通过了!
在这里插入图片描述
现在我们知道,这个函数又能正确地处理像 Janis Joplin 这样的姓名了,而且深信它也能够正确地处理像 Wolfgang Amadeus Mozart 这样的姓名。

二、测试类

类的测试与函数的测试相似,我们所做的大部分工作是测试类中方法的行为。不过还是存在一些不同之处,下面编写一个要测试的类:

class AnonymousSurvey:"""收集匿名调查问卷的答案。"""def __init__(self,question):"""存储一个问题,并为存储答案做准备。"""self.question = questionself.responses = []def show_question(self):"""显示调查问卷。"""print(self.question)def store_response(self,new_response):"""存储单份调查答卷。"""self.responses.append(new_response)def show_results(self):"""显示收集到的所有答卷。"""print("Survey results:")for response in self.responses:print(f"- {response}")

为证明 AnonymousSurvey 类能够正确工作,编写一个使用它的程序:

from survey import AnonymousSurvey# 定义一个问题,并创建一个调查。
question = "What language did you first learn to speak?"
my_survey = AnonymousSurvey(question)# 显示问题并存储答案。
my_survey.show_question()
print("Enter 'q'at any time to quit.\n")
while True:response = input("Language:")if response == 'q':breakmy_survey.store_response(response)# 显示调查结果。
print("\nThank you to everyone who participated in the survey!")
my_survey.show_results()

执行结果如下:
在这里插入图片描述

2.1 单个测试案例

下面来编写一个测试,对 AnonymousSurvey 类的行为的一个方面进行验证:如果用户面对调查问题只提供一个答案,这个答案也能被妥善地存储。为此,我们将在这个答案被存储后,使用方法 assertIn() 来核实它确实在答案列表中:

import unittest
from survey import AnonymousSurveyclass TestAnonymousSurvey(unittest.TestCase):"""针对AnonymousSurvey类的测试。"""def test_store_single_response(self):"""测试单个答案会被妥善地存储。"""question = "What language did you first learn to speak?"my_survey = AnonymousSurvey(question)  # 创建实例my_survey.store_response('English')self.assertIn('English',my_survey.responses)if __name__ == '__main__':unittest.main()

注意:要测试类的行为,需要创建其实例。

运行上述代码,我们看到测试通过了:
在这里插入图片描述

2.2 多个测试案例

我们可以像测试函数一样定义多个以 “test_” 开头地函数来测试类的不同方面,这时我们需要在每个函数下都要对被测试的类进行实例化。

unittest.TestCase 类包含的方法 setUp() 让我们只需创建这些对象一次,就能在每个测试方法中使用:如果在 TestCase 类中包含了方法 setUp(),Python 将先运行它,再运行各个以 “test_” 打头的方法。这样,在我们编写的每个测试方法中,都可使用在方法 setUp() 中创建的对象。

下面使用 setUp() 来创建一个调查对象和一组答案,供方法 test_store_single_response()test_store_three_responses()使用:

import unittest
from survey import AnonymousSurveyclass TestAnonymousSurvey(unittest.TestCase):"""针对AnonymousSurvey类的测试。"""def setUp(self):"""创建一个调查对象和一组答案,供使用的测试方法使用。"""question = "What language did you first learn to speak?"self.my_survey = AnonymousSurvey(question)self.responses = ['English','Spanish','Mandarin']def test_store_single_response(self):"""测试单个答案会被妥善地存储。"""self.my_survey.store_response(self.responses[0])self.assertIn(self.responses[0],self.my_survey.responses)def test_store_three_responses(self):"""测试三个答案会被妥善地存储。"""for response in self.responses:self.my_survey.store_response(response)for response in self.responses:self.assertIn(response,self.my_survey.responses)if __name__ == '__main__':unittest.main()

运行结果如下:
在这里插入图片描述
测试自己编写的类时,方法 setUp() 让测试方法编写起来更容易:可在 setUp() 方法中创建一系列实例并设置其属性,再在测试方法中直接使用这些实例。相比于在每个测试方法中都创建实例并设置其属性,这要容易得多。

三、总结

在本文中,我们学习了:如何使用模块 unittest 中的工具来为函数和类编写测试,如何编写继承 unittest.TestCase 的类,以及如何编写测试方法,以核实函数和类的行为符合预期;如何使用方法 setUp() 来根据类高效地创建实例并设置其属性,以便在类的所有测试方法中使用。

在这里插入图片描述

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

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

相关文章

第六十八:iview里的table,每行数据如果有满足条件的怎么更改颜色

当然了&#xff0c;肯定又是插槽&#xff0c;话不多说直接贴图 话不多说&#xff0c;直接贴代码 <Table :columns"columns" :data"data" border show-summary height"300" sum-text"汇总" v-else :summary-method"handleSumma…

YOLO目标检测综述(2024.6月最新!)

1 基本概念 目标检测&#xff08;Object Detection&#xff09;是计算机视觉领域的重要任务之一&#xff0c;旨在识别图像或视频中的特定目标并将其位置标记出来。与图像分类任务不同&#xff0c;目标检测要求不仅能够识别目标类别&#xff0c;还需要精确地定位目标的位置。由于…

OpenAI封锁中国?国产大模型开启价格战?收好这份LLM选购指南,带你搞定极致性价比 | ShowMeAI

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; 1. Cloud LLM capability, cost, performance | 一份开发者最实用的大模型「性价比」计算手册 这是 Harlan Lewis 整理的大语言模型 (LLM) 对比清单…

3d合并模型一直加载有哪些原因---模大狮模型网

当在3D软件中合并3d模型时&#xff0c;可能会遇到加载时间过长或持续加载的情况。这可能是由以下原因之一引起的&#xff1a; 一&#xff1a;模型复杂度 合并的模型可能非常复杂&#xff0c;包含大量的面片、顶点或纹理等。这会增加加载和处理的时间。解决方法是优化模型&…

【第二周】基础语法学习

目录 前言初始化项目文件介绍基本介绍JSWXMLWXSS 常见组件基础组件视图容器match-mediamovable-area/viewpage-containerscroll-viewswiper 表单组件自定义组件 模板语法数据绑定单向数据绑定双向数据绑定 列表渲染条件渲染模板引用 事件系统事件类型事件绑定阻止冒泡互斥事件事…

股指期权交割日期是什么时候?在每个月几号?

今天带你了解股指期权交割日期是什么时候&#xff1f;在每个月几号&#xff1f;期权交割日是指合约到期之日&#xff0c;即投资者需要履行买卖合约的义务。 股指期权的交割日期通常是期权合约到期日的第三个星期五。如果这一天是公共假日&#xff0c;则交割日可能会提前到前一…

Transformers 安装及 google-t5/t5-small 机器翻译示例

文章目录 Github文档推荐文章简介安装官方示例google-t5/t5-small使用脚本进行训练Pytorch 机器翻译数据集下载数据集格式转换 Github https://github.com/huggingface/transformers 文档 https://huggingface.co/docs/transformers/indexhttps://github.com/huggingface/tr…

计算机二级Access操作题总结——综合应用

属性表相关 例1&#xff1a; 不允许输入和修改其中的数据→【是否锁定】 例2&#xff1a; 单击“退出”按钮(名为“bt2”)&#xff0c;调用设计好的宏“mEmp”来关闭窗体。 分组和汇总 对“rSell”报表进行适当设置&#xff0c;使每名雇员的姓名显示在该雇员所售书籍信…

三品PDM项目成功上线 垣发集团携手三品软件迈向智能未来

项目背景 随着全球工业化和城市化进程的不断加快&#xff0c;高空作业车的市场需求日益增长。河南垣发专用车辆集团有限公司&#xff08;以下简称“垣发集团”&#xff09;自2014年成立以来&#xff0c;一直专注于高空作业车系列产品的研发与制造。 作为一家科技导向型企业&am…

Java AWT BorderLayout的使用

目录 背景: 代码例子: 代码详解: 效果展示: 总结: 背景: BoderLayout是Java AWT(Abstract Window Toolkit)和Swing图形用户界面(GUI)库中的一个布局管理器。它用于安排组件(如按钮、标签、面板等)在容器(如窗户、面板等)中的位置。BorderLayout容器划分为五个区域:北(NO…

硬盘空间告急?监控服务器容量,钉钉及时提醒!

在日常的服务器维护中&#xff0c;硬盘容量的监控是非常重要的。如果硬盘容量超过某个阈值&#xff0c;可能会导致服务器无法正常运行&#xff0c;影响业务的正常运作。为了避免这种情况&#xff0c;我们可以编写一个Shell脚本&#xff0c;定期检查硬盘容量&#xff0c;当超过设…

微服务框架中的Eureka和Ribbon的个人理解

微服务框架需要学习的东西很多&#xff0c;基本上我把它分为了五个模块&#xff1a; 第一&#xff1a;微服务技术模块 分为三个常用小模块&#xff1a; 1.微服务治理&#xff1a; 注册发现 远程调用 配置管理 网关路由 2.微服务保护&#xff1a; 流量控制 系统保护 熔断降级 服…

springcloud第4季 分布式事务seata实现AT模式案例

一 seata案例 1.1 背景说明 本案例使用seata的at模式&#xff0c;模拟分布式事务场景&#xff1a;【下订单&#xff0c;减库存&#xff0c;扣余额&#xff0c;改状态】 1.2 初始化脚本 1.2.1 新建seata_order_024 库 1.新建undol_log表 -- for AT mode you must to init…

锐捷AP从其它项目拆下,怎么也加入不了到现在这个网络里来

环境: AP 产品型号:RG-RAP2260G 问题描述: 锐捷AP从其它项目拆下,怎么也加入不了到现在这个网络里来,现网是WIFI5的,想把2260G用来升级,恢复出厂设置后,插上网线,现网找不到这个AP 解决方案: 1.通电重置AP后,连接AP WiFi进入管理页面,要求先快速配置 2.开始配置…

MySQL的隔离级别详解

MySQL的隔离级别详解 MySQL是一个广泛使用的关系数据库管理系统&#xff0c;其事务处理能力是其核心功能之一。事务处理中的隔离级别决定了一个事务在读取或写入数据时如何受到其他并发事务的影响。MySQL提供了四种标准的隔离级别&#xff0c;每种隔离级别在性能和一致性之间做…

算法力扣刷题记录十【19.删除链表的倒数第N个节点】

前言 链表练习&#xff0c;继续 题目&#xff1a;力扣【19.删除链表的倒数第N个节点】 题目阅读 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1…

服务器出现意外情况。(Exception from HRESULT: 0x80010105(RPC E SERVERFAULT))

这种情况一般出现在excel2007版本&#xff0c;下载了什么阅读器之类的 2007改不了这个加载项&#xff0c;需要重装一个其他版本&#xff08;2010版本可以&#xff09; 然后如下操作修改为COM加载项

Python湍流隐式模型耗散粘性方程和大涡流模拟

&#x1f3af;要点 &#x1f3af;达朗贝尔一维波动通解&#xff0c;二维变速模拟 | &#x1f3af;达朗贝尔算子解双曲波形微分方程 | &#x1f3af;耗散系统粘性伯格斯方程快速傅里叶变换算法 | &#x1f3af;二维线性和非线性对流扩散解和湍流隐式建模 &#x1f4dc;偏微分方…

[行业原型] Web端原型案例:康欣医疗后台管理系统

​医疗管理系统是一个业务复杂&#xff0c;功能庞大的系统&#xff0c;以下为HIS医院管理系统的常见模块&#xff0c;供大家参考。 本周为大家带来Web端原型案例&#xff1a;康欣医疗后台管理系统&#xff0c;先上原型&#xff1a; 完整文档加班主任微信号 添加班主任回复 “1…

8个Unity开发高手都在用的秘密技巧!

1. 不要重新发明轮子&#xff0c;使用内置的引擎工具 在使用任何引擎时&#xff0c;比如Unity或Unreal Engine&#xff0c;一些开发者&#xff0c;主要是来自计算机科学领域的开发者&#xff0c;可能会倾向于从头开始开发大型算法或结构&#xff0c;而不去了解引擎中是否已经存…