兔c同学的一篇:使用python 的 unittest模块对类和函数进行测试

news2024/11/27 1:29:50

文章目录

        • 1. 测试函数
            • 简单的函数测试
            • 单元测试和测试用例
            • 可通过的测试
            • 不可通过的测试
            • 测试未通过时怎么办
        • 2. 测试类
            • 各种断言方法
            • 测试一个类
            • 测试 AnonymousSurvey
            • 方法setUp()

导言

在编写函数或类时,还可为其编写测试。通过测试,可以确定代码面对各种输入都能够按要求的那样工作。或者在程序添加新的代码功能时,你也可以对其进行测试,确认它们不会破坏程序既有的作为。程序员都会犯错,因此每个程序员都必须经常测试其代码,在用户发现问题前找出它们。
本章,我们将讲述如何使用 python 的 unittest 中的工具来测试代码,我们进行编写测试用例,核实一系列输入都将得到预期的输出。我们可以看到通过测试将会是什么样子,测试未通过又是什么样子,还将知道测试未通过如何有助于改进代码。你将学习如何测试函数和类,并将知道该为项目编写多少个测试。

1. 测试函数

简单的函数测试

进行函数测试的前提是有可以进行测试的代码。
我们先编写一个简单的函数,它接受名和姓并返回整洁的姓名:

def get_name(first,last):
	name = first +" "+last
	return name.title()

现在我们开始编写测试代码,
我们可以用前面章节学到的知识进行结合,模拟一个用户输入信息的场景,
当用户输入完成自己的用户名信息后,给其返回他录入的信息,告诉他定义的信息为:


from name_test import get_name

print('您已成功登陆系统,请录入您的用户名.....')

while True:
	firstname = input('请录入您的姓氏:')
	lastname = input('请您继续存储您的名称:')
	
	names = get_name(firstname,lastname)
	print("您注册的用户名称为:"+ names)

经测试运行后发现,我们编写的返回姓名信息的函数逻辑是正确可行的。


单元测试和测试用例

python 标准库中的模块 unittest提供了代码测试工具。单元测试用于核实函数的某个方面没有问题;
测试用例考虑到了函数可能收到的各种输入,包含针对所有这些情形的测试。全覆盖式测试用例包含一整套单元测试,涵盖了各种可能的函数使用方式。对于大型项目,要实现全覆盖可能很难。通常,最初只要针对代码的重要行为编写测试即可,等项目被广泛使用时再考虑全覆盖。


可通过的测试

创建测试用例的语法需要一段时间才能习惯,但测试用例创建后,再添加针对函数的单元测试就很简单了。

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

#导入单元测试
import unittest

#导入进行测试的函数
from name_test import get_name

#创建类,用于包含一系列针对测试函数的单元测试
class NamesTestCase(unittest.TestCase):
	
	#开始进行函数测试
	def test_first_last_name(self):
		name = get_name('兔','c')
		
		self.assertEqual(name,'兔 C')

unittest.main()

编写的这段单元测试代码,测试的上一小节知识点中定义的 get_name()函数。
在这个代码中,导入了两个类,我们先看一下运行结果,在来解释代码行。

看看运行结果,到底能否通过调用 get_name()函数 返回名字。
在这里插入图片描述

第一行的句点表明有一个测试通过了。接下来的一行指出python运行了一个测试,消耗的时间不到0.001秒。最后一行的ok表示该测试用例中的单元测试都通过了。

接下来,我们开始逐行解释单元测试中的代码行。

首先,我们导入了模块 unittest,还有要进行测试的 get_name() 函数。
然后,我们又创建了一个类,类名为 NamesTestCase,用于包含一系列针对get_name的单元测试。至于类的命名规范一定要与进行测试的内容相关,并且还要包含Test字样。除了这些规范,还一定要继承 unittest.TestCase类,这样 python 才会知道如何运行你编写的测试。


NamesTestCase 只包含一个方法,用于测试 get_name() 函数的一个方法。我们将这个方法命名为 test_name_last_name()。因为我们要核实的是只有名和姓的姓名能否被正确的格式化。
当我们运行当前这个类的后缀为.py 文件时,所有 以 test 打头的方法都将自动运行。在这个方法中,我们调用了要测试的函数,并存储了要测试的返回值。在这个示例中,我们使用实参 ‘兔’ 和 'c’调用 get_name(),并将返回的结果存储到 name 变量当中。


unittest 类最有用的功能之一:一个断言方法。断言方法用来核实得到的结果是否与期望的结果一致。在这里,我们知道 get_name() 应返回这样的姓名,集名和姓的拼接,如果是英文,就以首字母大写的形式返回。
为了检查返回的内容和我们输入的内容是否一致,我们调用 unittest 的方法:assertEqual() ,至于这个方法中需要传递的参数,1 是变量,也就是存储了 获得到get_name 函数返回内容的变量。2 是 与其相对应的内容。也就是手动录入字符串内容,和其变量中存储的内容进行比对,当然这个比对是通过 asertEqual() 函数进行的。
最后,如果内容相等,就会返回如上图中的结果,反之,它会告诉我们错误信息。


不可通过的测试

什么样的测试不可通过呢?
例如上述示例中,我们定义的 get_name函数只能接收两个参数,但是并非所有人的名字都是两个字的,如果出现三个字的情况呢?

接下里,我们就测试一下三个字的名字,在调用 unittest.assertEqual() 函数进行校对:

import unittest
from name_test import get_name

class NamesTestCase(unittest.TestCase):
	#单元测试类中的函数一定要以test开头,才会在测试类启动时自动运行
	def test_first_last_name(self):
		name = get_name('兔','c','c')
		self.assertEqual(name,'兔CC')
		
unittest.main()

看一下运行结果:
在这里插入图片描述
python 解释器开始向我们说明错误了:

可以看到其中包含的信息很多,因为测试未通过。
第一行输出了一个字母E,它指出测试用例中有一个单元测试导致了错误。并且也给我们指出了错误所在行。
测试用例在包含众多单元测试时,知道哪个测试未通过至关重要,traceback,指出函数调用的有问题。
这里我们知道,自己定义的get_name 函数只能接收两个形参,而我们却传递了三个实参。


测试未通过时怎么办

如果你检查的条件没有错误,那说明测试通过了,也意味着函数的行为是对的。
而测试未通过就意味着我们编写的代码有问题了,因此,测试未通过时,不要修改测试,而应修复导致测试不能通过的代码:检查刚对函数所做的修改,找出导致函数行为不符合预期的修改。

现在,我们要做的就是去修改get_name() 函数了:

def get_name(first,last,middle =''):
	if middle:
		name = first + ' ' + middle + ' ' + last
	else:
		name = first + ' ' + last
	return name.title()

改好了 get_name 函数,我们在执行一下刚才的单元测试:
在这里插入图片描述
可以看到,现在的测试结果就通过了。


2. 测试类

上半部分,我们编写了针对函数的测试用例。下面,我们将接触针对类的测试。在很多程序中都会用到类,因此能够证明你的类能够正确地工作会大有裨益。如果针对类的测试通过了,你就能确信对类所做的改进没有意外地破坏其原有的行为。

各种断言方法

python 在 unittest 模块中提供了很多断言方法。
我们前面探讨过,断言方法检查认为应该满足的条件是否确实满足。如果该条件满足,你对程序行为的假设得到了确认,你就可以确信其中没有错误。如果你认为应该满足的条件实际上并不满足,python 将引发异常。

下面我们来列举 六个常用的断言方法:

使用试着方法可以核实返回的值等于或不等于预期的值,返回的值为True 或 False,返回的值在列表中或不在列表中。你只能在继承 unittest.TestCase的类中使用这些方法。

方法用途
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中

测试一个类

类的测试与函数的测试相似——你所做的大部分工作都是测试类中方法的行为,但存在一些不同之处,下面来编写一个类进行测试。

一个帮助管理匿名调查的类:

class AnonymousSurvey():
	"""收集匿名调查问卷的答案"""
	
	#初始化方法:存储一个问题,并为存储答案做准备
	def __init__(self,question):
		self.question = question
		#空列表用于存储收集到的答案
		self.response = []
		
	#调查问题的方法	
	def show_question(self):
		print(self.question)
		
	#添加新答案的方法
	def store_response(self,new_response):
		self.response.append(new_response)
	
	#显示收集到的所有答案
	def show_results(self):
		for response in self.response:
			print('-调查结果: '+response)

我们用刚定义好的 AnonymousSurvey 类描述收集匿名调查问卷的答案。
其中:
__ init __ 初始化方法,用于收集一个问题,并将之后收集到的答案存储在空列表当中。
show_question 方法,用于调查问题。
store_response 方法,用于添加收集到的新答案。
show_results 方法,用于显示收集到的所有答案。


如果要想知道这个类能否正确地工作,我们需要编写一个使用它的类:

from survey import AnonymousSurvey

#定义一个问题
question ="可以邀请您来参与我们的程序员问卷活动吗?"
#并使用这个定义的问题创建 AnonymousSurvey对象
my_survey = AnonymousSurvey(question)

#显示问题
my_survey.show_question()
print('录入q键可终止调查活动.....')

while True:
	response = input('请问您最喜欢哪一门编程语言?')
	if response == 'q':
		break
	my_survey.store_response(response)
	
#显示调查结果:
print('感谢您对本次调查问卷活动的支持!')
my_survey.show_results()

现在,我们编写好了 用于进行匿名调查问卷的 AnonymousSurvey 类,还有对该类进行使用的类,我们看一下使用的效果:
在这里插入图片描述

如果现在要对 AnonymousSurvey 类进行修改,例如:允许每位用户输入多个答案时,就会导致可能不小心修改处理单个答案的方式。要确认在开发这个模块时没有被破坏既有行为,可以编写针对这个类的测试。

测试 AnonymousSurvey

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

import unittest
from survey import AnonymousSurvey

class TestAnonymousSurvey(unittest.TestCase):
	def test_store_single_language(self):
		question = '请问可以邀请你参与程序员调查问卷吗?'
		my_survey = AnonymousSurvey(question)
		my_survey.store_response('c') #进行单个答案的存储
		
		self.assertIn('c',my_survey.response)
unittest.main()

在这段代码中,我们先导入了 unittest模块和 AnonymousSurvey 类。
接着,我们开始定义测试类,并且让测试类继承 unittest模块下的 TestCase类,
然后开始在测试类中定义测试方法,注意:测试方法需要以test_开头,这样在执行这个文件时,类中的test方法都会被自动执行。
同样的,我们先进行提问的问题设置,设置好了之后,创建存储该问题的实例,接下来,我们在通过实例来调用它内部的存储方法,将参数存储进去。
之后,调用核实内容是否在其内部的函数进行校对。

我们来看一下测试结果:
在这里插入图片描述
这很好,证明我们的代码都没有什么问题。可是只能收集一个答案的调查用途不大。
下面我们来核实用户提供三个答案时,它们也将被妥善地存储,为此,我们需要在 TestAnonymousSurvey 中再添加一个方法:

def test_stroe_three_response(self):
		#设置调查问题
		question = '请问您最喜欢哪一门编程语言?'
		#创建实例,并存储问题
		my_survey = AnonymousSurvey(question)

		#存储答案
		responses =['c','java','python']
		#遍历列表,将列表元素存储到调查问卷答案列表中
		for response in responses:
			my_survey.store_response(response)
		#再次遍历列表,调用 校对是否包含内容的assertIn方法
		for response in responses:
			self.assertIn(response,my_survey.response)

这次,我将代码行的逐行含义写在了注释中。
我们来看一下这个测试函数的测试结果:
在这里插入图片描述

方法setUp()

在前面的测试实例中,我们在每个测试方法中都创建了一个 AnonymousSurvey 实例,并在每个方法中都创建了答案。unittest.TestCase类包含方法 setUp(),让我们只需创建这些对象一次,并能够在每个测试方法中使用它们。

如果你在 TestCase类中包含了 setUp() 方法,python 将先运行它,再运行各个以test_打头的方法。这样,在你编写的每个测试方法中都可使用在方法setUp()中创建的对象了。

现在我们就使用 setUp()来创建一个调查对象和一组答案,供方法test_store_single_response() 和 test_store_three_responses() 使用:

from survey import AnonymousSurvey

class TestAnonymousSurvey(unittest.TestCase):
	def setUp(self):
		"""创建一个对象和一组答案,供使用的测试方法使用"""
		question = '请问你最喜欢哪一门编程语言?'
		self.my_survey = AnonymousSurvey(question)
		self.response = ['c','java','python']

	def test_store_single_language(self):
			self.my_survey.store_response(self.response[0])
			self.assertIn(self.response[0],self.my_survey.response)

	def test_store_three_responses(self):
			for response in self.response:
				self.my_survey.store_response(response)
			for response in self.response:
				self.assertIn(response,self.my_survey.response)
unittest.main()

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

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

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

相关文章

面试官必问--谈谈Spring Bean对象的生命周期吧

现在是时候讨论Spring Bean从产生到销毁整个过程的细节了,也就是Spring Bean的生命周期。在这里文哥先温馨提示:Spring Bean的生命周期是面试高频点之一,希望大家好好掌握哦~一. Spring Bean生命周期的概述如果没有Spring的环境,J…

张力控制之开环模式

张力控制的相关知识也可以参看专栏的其它文章,链接如下: 张力闭环控制之传感器篇(精密调节气阀应用)_RXXW_Dor的博客-CSDN博客跳舞轮对应张力调节范围,我们可以通过改变气缸的气压方式间接改变,张力跳舞轮在收放卷闭环控制上的详细应用,可以参看下面的文章链接,这里我…

人工智能实验一:利用遗传算法求解 TSP(旅行商)问题

1.任务描述 本关任务:利用遗传算法求解 TSP 问题。 2.相关知识 为了完成本关任务,你需要掌握:1. 遗传算法;2. TSP问题。 遗传算法 一个后继状态由两个父状态决定,以k个随机产生的状态开始(population&…

Kaggle赛题解析:Diffusion Prompt生成

文章目录一、比赛信息二、比赛背景三、比赛任务四、评价指标五、数据描述六、解题思路一、比赛信息 比赛名称:Stable Diffusion - Image to Prompts 推断生成高度详细、清晰的焦点、插图、宏伟、史诗般的 3d 渲染图像的prompt 比赛链接:https://www.k…

python----获取一部小说

1、需求说明 获取一部小说的标题内容,以txt文档形式保存 2、项目说明 3、代码 # 怎么发送请求 # pip install requests import requests# pip install lxml->从标签里提起文字 #from lxml import etree from lxml import html etreehtml.etree # 发送给谁 url…

Android---系统启动流程

目录 Android 系统启动流程 init 进程分析 init.rc 解析 Zygote 概叙 Zygote 触发过程 Zygote 启动过程 什么时Runtime? System Server 启动流程 Fork 函数 总结 面试题 Android 是 google 公司开发的一款基于 Linux 的开源操作系统。 Android 系统启动…

Web3中文|一波未平一波又起:Silvergate将走向何处

Silvergate Capital(SI)这一加密公司曾经的重要银行合作伙伴,现在正处于崩溃的边缘。这家总部位于加州拉荷亚的公司上周五晚上表示,其暂停了Silvergate交易所网络(SEN:Silvergate Exchange Network&#xf…

Foxit PDF SDK ActiveX 5.9.7 Crack

Foxit PDF SDK ActiveX对于刚接触PDF或不愿投入过多精力学习PDF技术的产品管理者及开发者来说,Foxit PDF SDK ActiveX无疑是理想的选择。破解版它拥有操作简单的特性,提供可支持定制的可视化编程组件,开发者通过简单的拖放动作,就…

扬帆配资|建筑业景气度持续回升,多只概念股业绩有望增长

新式城镇化概念股遭到商场重视。 今天早盘,新式城镇化概念股冲高,恒锋信息、ST花王涨停。蕾奥规划、筑博规划一度冲高至15%,冠龙节能、杭州园林、美晨生态跟涨。 国家出台一系列城镇化相关方针 城镇化,是人口向城镇会集的进程。…

【Kubernetes】第二十三篇 - 布署 nodejs 后端项目(上)

一,前言 上一篇,介绍了 MySQL 服务的部署; 本篇,介绍 nodejs 后端项目的布署(将后端项目构建成为 docker 镜像,并推送至镜像仓库); 二,准备项目 创建后端项目&#xf…

8、LSM树

一、前言 最近在调研NoSQL数据库,发现RocksDB、LevelDB、HBase以及Prometheus等,其底层的存储引擎都是基于LSM树,于是决定花时间彻底吃透LSM树这一数据结构。 不幸的是,在查阅资料学习的过程中,发现网上各种文章汗牛…

浅谈对Promise的理解以及在工作中的应用

浅谈对Promise的理解以及在工作中的应用Promise的概念背景知识JavaScript的同步和异步JavaScript事件循环回调函数进行异步操作解决方案:PromisePromise 在工作中的运用创建PromisePromise封装AJAXPromise链式操作Promise.all()Promise.race()async和await总结Promi…

轻松转换文档:antennahouse/Office Server Document Converter

关于 Office Server 文档转换器 (OSDC)破解版 无需 Microsoft Office 或 Adob​​e 软件即可快速准确地转换文档。 Office Server 文档转换器 (OSDC) 会将您在 Microsoft Office(Word、Excel、PowerPoint)中创建的重要文档转换为高质量的 PDF 或图像格式…

国内32位MCU在电机控制上的应用方案

电机(Electric machinery,俗称“马达”)是依据电磁感应定律,实现电能转换或传递的一种电磁装置,其主要作用是产生驱动转矩,为用电器或各类机械提供动力。电机作为工业世界的动力之源,几乎用于所…

ThinkPHP 6.1 模板篇之布局与继承

本文主要讲述ThinkPHP 6.1版本模板几种布局的方法和如何实现继承, 可以与《ThinkPHP 6.1 模板篇之文件加载》结合来看。 模板布局 布局方式有两种可以实现。 布局方法1 开启配置 默认情况下,不支持模版布局功能,需要在配置文件中开启&…

如何快速通过PMP考试?

我建议准备的最短时间至少一个月,我用了一个半月,我每天集中精力备考大约4个小时,大家可以根据自己的专注力的长短去调节每天的备考时间。 准备5月的,还没备考的,现在开始也来得及。5月没有报名的可以准备8月的&#…

【Linux系统编程】05:多进程

多进程 OVERVIEW多进程一、进程创建1.创建1个子进程2.创建多个子进程二、进程控制1.进程结束2.进程等待3.子进程操作14.子进程操作2三、进程体系1.守护进程2.进程调度程序:一种已经编译好的、存在磁盘中的二进制文件(脚本为普通文件)。进程&a…

超图iServer扩展开发记录Restlet 3

HTTP 请求在达到 REST 应用对象,交给资源实现类处理的时候,先要解析 HTTP 请求中的参数,然后才会进入业务逻辑进行处理。参数解析的工作由参数解析器(Decoder)进行,即可以实现将请求参数转换为 Java 对象。…

qt tcp通讯

TCP 协议(Transmission Control Protocol)全称是传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。tcp服务端使用QTcpServer、QTcpSocket。tcp客户端使用QTcpSocket1.在工程文件(工程文件.pro)中的第一行添加network 如QT core gui …

WeSpeaker支持C++部署链路

WeSpeaker正式更新C部署链路,推理引擎使用OnnxRuntime,支持从语音中提取Speaker Embedding信息,代码详见WeSpeaker/runtime[1]。 Libtorch和onnx的选择? Speaker Embedding提取任务流程简单,并且声纹模型(如ResNet\E…