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

news2024/9/9 4:00:46

目录

  • 一、测试函数
    • 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_name

print("Enter 'q' at any time to quit.")
while True:
    first = input("\nPlease give me a first name:")
    if first == 'q':
        break
    last = input("Please give me a last name:")
    if last == 'q':
        break

    formatted_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_name

class 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_name

class 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 = question
        self.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':
        break
    my_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 AnonymousSurvey

class 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 AnonymousSurvey

class 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.coloradmin.cn/o/1870630.html

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

相关文章

Jenkins教程-9-发送企业微信测试报告通知

上一小节我们学习了Jenkins上下游关联自动化测试任务的构建的方法,本小节我们讲解一下发送企业微信测试报告通知的方法。 1、自动化用例执行完后,使用pytest_terminal_summary钩子函数收集测试结果,存入本地status.txt文件中,供J…

Arathi Basin (AB) PVP15

Arathi Basin (AB) PVP15 阿拉希盆地,PVP,15人战场

【银河麒麟】高可用触发服务器异常重启,处理机制详解

1.服务器环境以及配置 【机型】物理机 处理器: Intel 内存: 126G 【内核版本】 4.19.90-25.16.v2101.ky10.x86_64 【银河麒麟操作系统镜像版本】 Kylin-Server-10-SP2-Release-Shenzhen-Metro-x86-Build01-20220619 Kylin-HA-10-SP2-Release-S…

前端vue3 根据某些Id 筛选数据

现在有一些不等的数据 我需要通过前端 吧这个数据筛选一下 比如我使用一些 我需要的ID 下的数据 比如以上的数据 的 cinemaLineId 来筛选 const cinemaLineId ref(["1246429254713147392", "1182608813770321920", "1182608917403185152"])…

大数据之Hadoop部署

文章目录 服务器规划服务器环境准备1. 网络测试2. 安装额外软件包3. 安装基础工具4. 关闭防火墙5. 创建用户并配置权限6. 创建目录并设置权限7. 卸载JDK8. 修改主机名9. 配置hosts文件10. 重启服务器 配置免密登录安装Java安装Hadoop1. Hadoop部署2. 配置Hadoop3. 格式化Hadoop…

【PyQt5】一文向您详细介绍 QVBoxLayout() 的作用

【PyQt5】一文向您详细介绍 QVBoxLayout() 的作用 下滑即可查看博客内容 🌈 欢迎莅临我的个人主页 👈这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地!🎇 🎓 博主简介:985高校的普通本硕&a…

机器人控制系列教程之URDF文件语法介绍

前两期推文:机器人控制系列教程之动力学建模(1)、机器人控制系列教程之动力学建模(2),我们主要从数学的角度介绍了机器人的动力学建模的方式,随着机器人技术的不断发展,机器人建模成为了机器人系统设计中的一项关键任务。URDF&…

我只有一点Python基础,对学习WebGIS开发有帮助吗?

经常有人后台私信问,我只有一点Python基础,对学习GIS开发有帮助吗? 关于这个问题的答案是,当然有!Python适用于WebGIS开发。WebGIS是地理信息系统(GIS)技术与Web技术的结合,而Pytho…

Go语言学习:每日一练2

Go语言学习:每日一练2 目录 Go语言学习:每日一练2结构体零值数组切片映射指针 各个类型的零值一览 结构体 //定义 type Vertex struct {X, Y int } //使用 func main() { v1 : Vertex{1, 2} fmt.Println(v.X) //别的实例化方式 var v2 Vertex v2 : *new…

《PIDNet: A Real-time Semantic Segmentation Network Inspired by PID Controllers》

期刊:CVPR 年份:2023 代码:https://github.com/XuJiacong/PIDNet 摘要 双分支网络架构已经证明了它在实时语义分割任务中的有效性和有效性。然而,高分辨率细节和低频上下文的直接融合的缺点是细节特征很容易被周围的上下文信息…

Nuxt3 的生命周期和钩子函数(三)

title: Nuxt3 的生命周期和钩子函数(三) date: 2024/6/27 updated: 2024/6/27 author: cmdragon excerpt: 摘要:概述了Nuxt3的关键生命周期钩子用途,如page:finish用于页面加载后处理,page:transition:finish处理过…

MySQL数据库简介和安装

文章目录 一、数据库原理目前情况数据库的发展史RDBMS关系型数据库关系型数据库理论 二、MySQL历史发展历程关系型数据库和非关系型数据库 三、安装mysql及优化yum安装编译安装mysql二进制安装优化操作 四、 安装mycli插件客户端工具 一、数据库原理 目前情况 我们正处于一个…

十三、Maven(1)

🌻🌻目录 一、maven价绍二、maven的功能1、项目自动化构建2、管理jar、war包3、实现项目结构设计 三、maven安装1、maven的安装环境需要jdk2、Maven的安装路径中不能出现中文和空格3、压缩包解压即可4、配置环境变量 四、maven的仓库1. Maven仓库配置2. …

AI提示词投喂新手教程(一):基础概念和工具

对于很多已经熟悉提示词工程(prompt engineering)的朋友来说,以下内容可能已经是老生常谈了。然而,仔细搜索和翻阅了星球上关于提示词的新手教程,发现对新手并不是很友好,内容零散且缺乏系统性。为此&#…

Construct公司 从 0 到 1 基于 Kitex+Istio 的微服务系统建设

本文根据 2024 年 5 月 25 日在上海举办的“云原生✖️AI 时代的微服务架构与技术实践”CloudWeGo 技术沙龙上海站活动中,Construct 服务端总监 Jason 的演讲《从 0 到 1 基于 Kitex Istio 的微服务系统建设》整理而来。 在微服务架构的浪潮中,企业面临…

Android 通知组

一. 通知组简介 从 Android 7.0(API 级别 24)开始,您可以在一个组中显示相关通知。如下所示: 图 1. 收起(顶部)和展开(底部)的通知组。 注意 :如果应用发出 4 条或更多条通知且未…

【笔记】HashMap的头插死循环问题

HashMap头插死循环是指在JDK1.7中,多线程环境下,HashMap进行扩容时由于多个线程一起执行扩容,可能会导致某一结点被错误插入头部并形成一个循环链表。 发生死循环的源码如下: // hashmap由数组链表构成 void transfer(Entry[] ne…

【Micro-ROS学习】

Micro-ROS 是专为 ROS 2 设计的,它允许在微控制器(microcontrollers)上实现ROS 2的功能。Micro-ROS 从 ROS 2 架构优化而来,目的是让那些资源有限的嵌入式设备也能够接入ROS 2生态系统,享受ROS 2带来的标准化通信、模块…

放烟花短视频素材去哪里找?去哪里下载?烟花素材网分享

在当代社会,短视频凭借其独有的魅力成为大众传递情感、记录生活、分享快乐的新兴方式。特别是在庆祝节日和特殊时刻时,烟花的绚丽效果常常被用来吸引观众的目光,成为视频作品中的亮点。然而,对于短视频制作者来说,寻找…

【Web3】Web3.js 启动!并解决Web3 is not a constructor报错

苏泽 大家好 这里是苏泽 一个钟爱区块链技术的后端开发者 本篇专栏 ←持续记录本人自学智能合约学习笔记和经验总结 如果喜欢拜托三连支持~ 本节教大家如何启动Web3.js 目录 Web3 启动! 于是很愉快的报错 创建实例! 出来了 Web3:模块…