79、测试函数

函数get_formatted_name() 将名和姓合并成姓名,在名和姓之间加上一个空格,并将它们的首字母都大写,再返回结果。为核实get_formatted_name() 像期望的那样工作,我们来编写一个使用这个函数的程序。程序names.py让用户输入名和姓,并显示整洁的全名:

# -*- coding: utf-8 -*-
def get_formatted_name(first,last):
    """Generate a neatly formatted full name."""
    full_name = first + " " + last
    return  full_name.title()

再编写一段测试代码,从name_function.py中导入函数get_formatted_name() 。用户可输入一系列的名和姓,并看到格式整洁的全名:

# -*- coding: utf-8 -*-
from name_function import get_formatted_name

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

    formatted_name = get_formatted_name(first,last)
    print("\nNeatly formatted name: " + formatted_name + ".")

测试结果如下:

Enter 'q' at any time to quit.

Please give me a first name: janis
Please give me a last name: joplin

Neatly formatted name: Janis Joplin.

Please give me a first name: leilei
Please give me a last name: 23

Neatly formatted name: Leilei 23.

Please give me a first name: bob
Please give me a last name: dylan

Neatly formatted name: Bob Dylan.

Please give me a first name: q

Process finished with exit code 0

从测试的结果可以看到,得到的姓名正确无误。
可通过的测试
为函数编写测试用例,可先导入模块
unittest 以及要测试的函
数,再创建一个继承unittest.TestCase 的类,并编写一系列方法对函数行为的不同方面进行测试。

# -*- coding: utf-8 -*-
import unittest
from name_function import  get_formatted_name

class NamesTestCase(unittest.TestCase): # 子类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") # self.assertEqual测试代码并返回结果

unittest.main()

们使用了unittest 类的断言的方法用来核实得到的结果是否与期望的结果是否一致。我们知道在函数get_formatted_name中,输入"janis","joplin",最后得到的结果应为"Janis Joplin",接下来就看测试的结果是否是预测的那样。
代码行self.assertEqual(formatted_name, 'Janis Joplin') 的意思是说:“将formatted_name 的值同字符串'Janis Joplin' 进行比较,并把结果返回。
测试结果如下:

.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

Process finished with exit code 0

在测试结果中第1行的句点表明有一个测试通过了。
接下来的一行指出Python运行了一个测试,消耗的时间不到0.001秒。
最后的OK 表明该测试用例中的所有单元测试都通过了。
未通过的测试
我们来修改函数get_formatted_name() ,使其能够处理中间名,故意让这个函数无法正确地处理像Janis Joplin这样只有名和姓的姓名。

# -*- coding: utf-8 -*-
def get_formatted_name(first,middle,last):
    """Generate a neatly formatted full name."""
    full_name = first + " " + middle + " " +  last
    return  full_name.title()

再运行程序测试

# -*- coding: utf-8 -*-
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()

测试结果如下:

E
======================================================================
ERROR: test_first_last_name (__main__.NamesTestCase)
能否正确处理像Janis Joplin这样的姓名?
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:/Python/python_work/test/test_name_function.py", line 10, in test_first_last_name
    formatted_name = get_formatted_name("janis","joplin")
TypeError: get_formatted_name() takes exactly 3 arguments (2 given)

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (errors=1)

Process finished with exit code 1

从测试结果可以看出测试未通过。
其中第1行输出只有一个字母E,它指出测试用例中有一个单元测试导致了错误。
接下来可以看到出错的原因是:NamesTestCase 中的test_first_last_name() 函数导致了错误。
"Ran 1 test in 0.001s"这一句指出Python运行了一个测试,消耗的时间不到0.001秒。
"FAILED (errors=1)"这一句整个测试用例都未通过,因为运行该测试用例时发生了一个错误。

当遇到测试未通过时,先检查测试的条件是否有错,如果没错那就着重检查导致测试不能通过的代码:像上面的例子就要检查刚对函数所做的修改,找出导致函数行为不符合预期的修改。
在上述例子中,get_formatted_name() 函数以前只需要两个实参——名和姓,但现在它要求提供名、中间名和姓。因此,我们把新增的中间名变为可选的,可在函数定义中将形参
middle 移到形参列表末尾,并将其默认值指定为一个空字符串。我们还要添加一个if 测试,如果提供了中间名就创建 名 + 中间名 + 姓,如果不提供中间名就创建 名 + 姓
所以函数get_formatted_name()修改为:

# -*- coding: utf-8 -*-
def get_formatted_name(first,last,middle = ""):
    """生成整洁的姓名"""
    if middle:
        full_name = first + " " + middle + " " +  last
    else:
        full_name = first + " " +  last
    return  full_name.title()

测试结果为:

# -*- coding: utf-8 -*-
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()
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

Process finished with exit code 0

如果要增加测试中间名,我们需要在NamesTestCase 类中再添加一个方法:

# -*- coding: utf-8 -*-
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")

unittest.main()

测试结果:

..
----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

Process finished with exit code 0
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • 编写函数或类时,还可为其编写测试。通过测试,可确定代码面对各种输入都能够按要求的那样工作。在程序中添加新代码时,你...
    Darren_Lin阅读 5,234评论 1 5
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,580评论 18 139
  • 主要内容: 1.函数 2.类 3.异常处理 4.文件 8.函数 1.定义函数: 使用关键字def来告诉python...
    起个名字真难999阅读 453评论 0 2
  • Startup 单元测试的核心价值在于两点: 更加精确地定义某段代码的作用,从而使代码的耦合性更低 避免程序员写出...
    wuwenxiang阅读 10,081评论 1 27
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,560评论 18 399