测试函数

先写下要测试的代码:
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丨测试代码相关推荐

  1. 2.python爬虫实战:爬取近5年的中国大学排行榜信息【Python】(测试代码+api例程)

    目录 API说明: 思路 注意事项 完整代码 总结 欢迎关注 『Python』 系列,持续更新中 欢迎关注 『Python』 系列,持续更新中 爬取近5年的中国大学排行榜信息,在python爬虫爬取2 ...

  2. Python入门实例——测试代码

    文章目录 测试函数 单元测试和测试用例 测试类 各种断言方法 编写待测试的类 测试类 方法 setUp() 总结 测试函数 Python 模块 unittest 主要用来做测试代码使用,这样能够在自己 ...

  3. Python timeit库测试代码片段运行时间

    timeit库文档:https://docs.python.org/zh-cn/3/library/timeit.html timeit 是一个用来测量小代码片段执行时间的工具库,有命令行和函数调用两 ...

  4. python测试代码怎么写_Python 单元测试

    Test your software, or your users will. "Test ruthlessly. Don't make your users find bugs for y ...

  5. python代码测试工具模块_详解Python中的测试工具

    当我们在写程序的时候,我们需要通过测试来验证程序是否出错或者存在问题,但是,编写大量的测试来确保程序的每个细节都没问题会显得很繁琐.在Python中,我们可以借助一些标准模块来帮助我们自动完成测试过程 ...

  6. 十五、Python第十五课——测试代码

    (请先看这篇文章:https://blog.csdn.net/GenuineMonster/article/details/104495419) 也许你听过软件测试?编写函数或类时,可以为其编写对应的 ...

  7. 《Python编程从入门到实践》记录之测试代码(unitttest模块)

    unittest模块提供了测试代码工具. 单元测试:用于核实函数的某个方面没有问题 测试用例:一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求. 函数编写测试用例时,要导入模块uni ...

  8. python测试代码怎么写_如何使用python做单元测试?

    很多编程小白不太理解单元测试,为什么要进行单元测试呢?很简单,主要是提高代码的正确,同时确保重构不出错.接下来我们一起学习怎么用python做单元测试吧. python内置了一个unittest,但是 ...

  9. python的unittest测试类代码实例

    nittest单元测试框架不仅可以适用于单元测试,还可以适用WEB自动化测试用例的开发与执行,该测试框架可组织执行测试用例,并且提供了丰富的断言方法,判断测试用例是否通过,最终生成测试结果.今天笔者就 ...

最新文章

  1. 原来,王兴是理想汽车的「二当家」!股份只比李想少1.6%丨理想汽车招股书
  2. 15个最佳的代码评审(Code Review)工具
  3. UA MATH564 概率分布总结
  4. 不显示参数名_第51p,万能参数与返回值,Python中函数的返回值
  5. 美创意 -vue 组件的网站
  6. Ibatis 动态查询
  7. 错误解决办法:‘NULL’ was not declared in this scope
  8. C++异常处理之terminate函数和set_terminate()函数
  9. Linux进程管理工具
  10. 机器学习笔记(八):线性回归算法的评测标准 | 凌云时刻
  11. worldwind java 教程,如何脱机使用World Wind Java SDK
  12. AS-修改APP图标和名字
  13. Windows 10 网络和Internet设置中WLAN选项消失
  14. 2020年黄历表_2020年黄历表(死亡时辰吉凶对照表)
  15. 【初级篇】网页引入live2d
  16. FPGA--ZCU106通过SFP+/SGMII模块传输数据-第一讲(全网唯一)
  17. 关于鼠标手的症状和恢复方法
  18. 拼多多Temu如何批量养国外买家账号进行拉新?
  19. PaddlePaddle笔记4-看图写诗
  20. pgsql处理文档类型数据_PostgreSQL 基本数据类型及常用SQL 函数操作

热门文章

  1. 解决“事件ID(487)的描述(在资源(Zend Optimizer)中)无法找到”问题
  2. TCP与UDP 的区别
  3. 从Flink SQL doesn't support consuming update and delete changes 错误谈起
  4. Python下openCV打开图片的几种方式/适应窗口大小
  5. linux C -- ftok函数
  6. 测试服务器网站并发,Nginx服务器10000 并发 优化测试(ab测试工具)
  7. 模型选择准则之AIC和BIC
  8. IOS Label下划线 中划线
  9. UI设计是什么,就业前景怎么样?
  10. 上海交大考研823网络空间安全经验分享