(python)Day9丨测试代码
测试函数
先写下要测试的代码:
name_function.py
def get_formatted_name(first,last):"""Generate a neatly formatted full name"""full_name=first+' '+lastreturn 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':breaklast=input("\nPlease give me a last name:")if last=='q':breakformatted_name=get_formatted_name(first,last)print("\tNeatly formatted name: "+formatted_name)
单元测试和测试用例
- Python标准库中的模块unittest提供了代码测试工具。
- 单元测试用于核实函数的某个方面没有问题
- 测试用例是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求
- 良好的测试用例考虑到了函数可能收到的各种输入,包含针对所有这些情形的测试。
- 全覆盖式测试用例包含一整套单元测试,涵盖了各种可能的函数使用方式。
- 对于大型项目,要实现全覆盖可能很难。通常,最初只要针对代码的重要行为编写测试即可,等项目被广泛使用时再考虑全覆盖。
「就是一些注意点,知道就行了」
可通过的测试
要为函数编写测试用例,可先导入模块unittest以及要测试的函数。
再创建一个继承unittest.TestCase的类,并编写一系列方法对函数行为的不同方面进行测试。
【好吧,完全没有看懂,还是先看一下例子来理解吧。。。。】
下面是一个只包含一个方法的测试用例,它检查函数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')
unittest.main()
- 首先,我们导入了模块unittest和要测试的函数get_formatted_name()
- 然后,我们创建了一个名为NamesTestCase的类,用于包含一系列针对get_formatted_name()的单元测试。
- 这个类必须继承unittest.TestCase类,这样Python才知道如何运行你编写的测试。
- 我们运行testname_function.py时,所有以test打头的方法都将自动运行。
- 。在这个方法中,我们调用了要测试的函数,并存储了要测试的返回值。在这个示例中,我们使用实参’janis’和’joplin’调用get_formatted_name(),并将结果存储到变量formatted_name中
- 在倒数第二行,我们使用了unittest类最有用的功能之一:一个断言方法。断言方法用来核实得到的结果是否与期望的结果一致。
- 代码行self.assertEqual(formatted_name, ‘Janis Joplin’)的意思是说:“将formatted_name的值同字符串’Janis Joplin’进行比较,如果它们相等,就万事大吉,如果它们不相等,跟我说一声!
结果:
.
----------------------------------------------------------------------
Ran 1 test in 0.000sOK
- 第1行的句点表明有一个测试通过了。接
- 下来的一行指出Python运行了一个测试,消耗的时间不到0.001秒。
- 最后的OK表明该测试用例中的所有单元测试都通过了。
不能通过的测试
如果测试通过不了会是啥样呢?
下面修改一下get_formatted_name(),使其能够处理中间名,但这样做时,故意让这个函数无法正确地处理像Janis Joplin这样只有名和姓的姓名。
def get_formatted_name(first,middle,last):"""生成整洁的姓名"""full_name=first+' '+middle+' '+lastreturn full_name.title()
这个版本应该能够正确地处理包含中间名的姓名,但对其进行测试时,我们发现它再也不能正确地处理只有名和姓的姓名。这次运行程序test_name_function.py时,输出如下:
E#1
======================================================================
ERROR: test_first_last_name (__main__.NamesTestCase)#2
能够正确地处理像Janis Joplin这样地姓名么?
----------------------------------------------------------------------
Traceback (most recent call last):#3File "D:/python不知道啥/helloworld.py", line 7, in test_first_last_nameformatted_name=get_formatted_name('janis','joplin')
TypeError: get_formatted_name() missing 1 required positional argument: 'last'----------------------------------------------------------------------
Ran 1 test in 0.001s#4FAILED (errors=1)#5
- 第1行输出只有一个字母E(见❶),它指出测试用例中有一个单元测试导致了错误
- 接下来,我们看到NamesTestCase中的test_first_last_name()导致了错误(见❷)。测试用例包含众多单元测试时,知道哪个测试未通过至关重要。
- 在❸处,我们看到了一个标准的traceback,它指出函数调用get_formatted_name(‘janis’, ‘joplin’)有问题,因为它缺少一个必不可少的位置实参。
- 我们还看到运行了一个单元测试(见❹)。
- 最后,还看到了一条消息,它指出整个测试用例都未通过,因为运行该测试用例时发生了一个错误(见❺)。
- 这条消息位于输出末尾,让你一眼就能看到——你可不希望为获悉有多少测试未通过而翻阅长长的输出。
【能看懂错误显示也是非常有必要的】
测试未通过时怎么办
测试未通过时,不要修改测试,而应修复导致测试不能通过的代码:检查刚对函数所做的修改,找出导致函数行为不符合预期的修改。
下面来修改get_formatted_name(),将中间名设置为可选的,然后再次运行这个测试用例。如果通过了,我们接着确认这个函数能够妥善地处理中间名。
要将中间名设置为可选的,可在函数定义中将形参middle移到形参列表末尾,并将其默认值指定为一个空字符串。我们还要添加一个if测试,以便根据是否提供了中间名相应地创建姓名(这个之前做过,已经很熟了)
def get_formatted_name(first,last,middle=''):"""生成整洁的姓名"""if middle:full_name=first+' '+middle+' '+lastelse:full_name=first+' '+lastreturn full_name.title()
添加新测试
确定get_formatted_name()又能正确地处理简单的姓名后,我们再编写一个测试,用于测试包含中间名的姓名。为此,我们在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_last_middle_name(self):"""能够正确地处理像Wolfgang Amadeus Mozart这样的姓名吗?"""formatted_name=get_formatted_name('wolfgang','mozart','amadeus')self.assertEqual(formatted_name,'Wolfgang Amadeus Mozart')
unittest.main()
结果:
..
----------------------------------------------------------------------
Ran 2 tests in 0.000sOK
测试类
各种断言方法
下面是6个断言方法:
一个要测试的类
帮助管理匿名调查的类
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('-'+response)
为证明AnonymousSurvey类能够正确地工作,我们来编写一个使用它的程序
from survey import AnonymousSurvey
#定义一个问题,并创建一个表示调查的AnoymousSurvey对象
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()
测试AnonymousSurvey类
下面来编写一个测试,对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)
unittest.main()
要测试类的行为,需要创建其实例。我们使用问题"What language did you first learn to speak?"创建了一个名为my_survey的实例,然后使用方法store_response()存储了单个答案English。接下来,我们检查English是否包含在列表my_survey.responses中,以核实这个答案是否被妥善地存储了
这很好,但只能收集一个答案的调查用途不大。下面来核实用户提供三个答案时,它们也将被妥善地存储。为此,我们在TestAnonymousSurvey中再添加一个方法
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)def test_store_three_responses(self):question="What language did you first learn to speak?"my_survey=AnonymousSurvey(question)responses=['English','Spanish','Mandarin']for response in responses:my_survey.store_response(response)for response in responses:self.assertln(response,my_survey.responses)
unittest.main()
方法setUp()
在前面的test_survey.py中,我们在每个测试方法中都创建了一个AnonymousSurvey实例,并在每个方法中都创建了答案。
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)
unittest.main()
方法setUp()做了两件事情:
创建一个调查对象
self.my_survey=AnonymousSurvey(question)
创建一个答案列表:
self.responses=['English','Spanish','Mandarin']
存储这两样东西的变量名包含前缀self(即存储在属性中),因此可在这个类的任何地方使用。
这让两个测试方法都更简单,因为它们都不用创建调查对象和答案。
方法test_store_single_response()核实self.responses中的第一个答案——self.responses[0]——被妥善地存储.
而方法test_store_three_response()核实self.responses中的全部三个答案都被妥善地存储。
再次运行test_survey.py时,这两个测试也都通过了。
如果要扩展AnonymousSurvey,使其允许每位用户输入多个答案,这些测试将很有用。
修改代码以接受多个答案后,可运行这些测试,确认存储单个答案或一系列答案的行为未受影响。
测试自己编写的类时,方法setUp()让测试方法编写起来更容易:可在setUp()方法中创建一系列实例并设置它们的属性,再在测试方法中直接使用这些实例。相比于在每个测试方法中都创建实例并设置其属性,这要容易得多。
运行测试用例时,每完成一个单元测试,Python都打印一个字符:测试通过时打印一个句点;测试引发错误时打印一个E;测试导致断言失败时打印一个F。这就是你运行测试用例时,在输出的第一行中看到的句点和字符数量各不相同的原因。如果测试用例包含很多单元测试,需要运行很长时间,就可通过观察这些结果来获悉有多少个测试通过了。
学习感想
说实话,这节有点抽象,我翻来覆去地看了好几遍,还是有点不知所云,没有轻轻楚楚地掌握住。。。。反正大概有个印象了,以后要用到的时候再细细地看把
写到这里,该书的第一部分:基础知识已经全部结束啦!!下面就要开启项目了,我一定要好好地学,把之前学过的知识都好好用用!!
(python)Day9丨测试代码相关推荐
- 2.python爬虫实战:爬取近5年的中国大学排行榜信息【Python】(测试代码+api例程)
目录 API说明: 思路 注意事项 完整代码 总结 欢迎关注 『Python』 系列,持续更新中 欢迎关注 『Python』 系列,持续更新中 爬取近5年的中国大学排行榜信息,在python爬虫爬取2 ...
- Python入门实例——测试代码
文章目录 测试函数 单元测试和测试用例 测试类 各种断言方法 编写待测试的类 测试类 方法 setUp() 总结 测试函数 Python 模块 unittest 主要用来做测试代码使用,这样能够在自己 ...
- Python timeit库测试代码片段运行时间
timeit库文档:https://docs.python.org/zh-cn/3/library/timeit.html timeit 是一个用来测量小代码片段执行时间的工具库,有命令行和函数调用两 ...
- python测试代码怎么写_Python 单元测试
Test your software, or your users will. "Test ruthlessly. Don't make your users find bugs for y ...
- python代码测试工具模块_详解Python中的测试工具
当我们在写程序的时候,我们需要通过测试来验证程序是否出错或者存在问题,但是,编写大量的测试来确保程序的每个细节都没问题会显得很繁琐.在Python中,我们可以借助一些标准模块来帮助我们自动完成测试过程 ...
- 十五、Python第十五课——测试代码
(请先看这篇文章:https://blog.csdn.net/GenuineMonster/article/details/104495419) 也许你听过软件测试?编写函数或类时,可以为其编写对应的 ...
- 《Python编程从入门到实践》记录之测试代码(unitttest模块)
unittest模块提供了测试代码工具. 单元测试:用于核实函数的某个方面没有问题 测试用例:一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求. 函数编写测试用例时,要导入模块uni ...
- python测试代码怎么写_如何使用python做单元测试?
很多编程小白不太理解单元测试,为什么要进行单元测试呢?很简单,主要是提高代码的正确,同时确保重构不出错.接下来我们一起学习怎么用python做单元测试吧. python内置了一个unittest,但是 ...
- python的unittest测试类代码实例
nittest单元测试框架不仅可以适用于单元测试,还可以适用WEB自动化测试用例的开发与执行,该测试框架可组织执行测试用例,并且提供了丰富的断言方法,判断测试用例是否通过,最终生成测试结果.今天笔者就 ...
最新文章
- 原来,王兴是理想汽车的「二当家」!股份只比李想少1.6%丨理想汽车招股书
- 15个最佳的代码评审(Code Review)工具
- UA MATH564 概率分布总结
- 不显示参数名_第51p,万能参数与返回值,Python中函数的返回值
- 美创意 -vue 组件的网站
- Ibatis 动态查询
- 错误解决办法:‘NULL’ was not declared in this scope
- C++异常处理之terminate函数和set_terminate()函数
- Linux进程管理工具
- 机器学习笔记(八):线性回归算法的评测标准 | 凌云时刻
- worldwind java 教程,如何脱机使用World Wind Java SDK
- AS-修改APP图标和名字
- Windows 10 网络和Internet设置中WLAN选项消失
- 2020年黄历表_2020年黄历表(死亡时辰吉凶对照表)
- 【初级篇】网页引入live2d
- FPGA--ZCU106通过SFP+/SGMII模块传输数据-第一讲(全网唯一)
- 关于鼠标手的症状和恢复方法
- 拼多多Temu如何批量养国外买家账号进行拉新?
- PaddlePaddle笔记4-看图写诗
- pgsql处理文档类型数据_PostgreSQL 基本数据类型及常用SQL 函数操作
热门文章
- 解决“事件ID(487)的描述(在资源(Zend Optimizer)中)无法找到”问题
- TCP与UDP 的区别
- 从Flink SQL doesn't support consuming update and delete changes 错误谈起
- Python下openCV打开图片的几种方式/适应窗口大小
- linux C -- ftok函数
- 测试服务器网站并发,Nginx服务器10000 并发 优化测试(ab测试工具)
- 模型选择准则之AIC和BIC
- IOS Label下划线 中划线
- UI设计是什么,就业前景怎么样?
- 上海交大考研823网络空间安全经验分享