第 11 章 测试代码

第 11 章 测试代码

通过测试,可确定代码面对各种输入都能够按要求的那样工作。测试让你信心满满,深信即便有更多的人使用你的程序,它也 能正确地工作。在程序中添加新代码时,你也可以对其进行测试,确认它们不会破坏程序既有的行为.

11.1 测试函数

name:

def get_formatted_name(first, last): full_name = first + ' ' + last return full_name.title()

names:

from name 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("\tNeatly formatted name: " + formatted_name + '.')
11.1.1 单元测试和测试用例

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

11.1.2 可通过的测试
import unittest
from name import get_formatted_name
class NamesTestCase(unittest.TestCase):
    def test_first_last_name(self):
        formatted_name = get_formatted_name('janis', 'joplin')
        self.assertEqual(formatted_name, 'Janis Joplin')
if __name__=='__main__':
    unittest.main()

导入了模块unittest 和要测试的函数get_formatted_name().创建了一个名为NamesTestCase 的类,用于包含一系列针 对get_formatted_name() 的单元测试。使用了unittest 类最有用的功能之一:一个断言断言 方法。断言方法用来核实得到的结果是否与期望的结果一致。在这里,我们知道get_formatted_name() 应 返回这样的姓名,即名和姓的首字母为大写,且它们之间有一个空格,因此我们期望formatted_name 的值为Janis Joplin 。为检查是否确实如此,我们调用unittest 的方法assertEqual() ,并向它传递formatted_name 和'Janis Joplin' 。代码行self.assertEqual(formatted_name, 'Janis Joplin') 的意思是 说:“将formatted_name 的值同字符串'Janis Joplin' 进行比较,如果它们相等,就万事大吉,如果它们不相等,跟我说一声!

11.1.3 不能通过的测试

将name.py改为:

def get_formatted_name(first,middle, last):
    full_name = first + ' ' + middle + ' ' + last
    return full_name.title()

在运行代码

import unittest
from name import get_formatted_name
class NamesTestCase(unittest.TestCase):
    def test_first_last_name(self):
        formatted_name = get_formatted_name('janis', 'joplin')
        self.assertEqual(formatted_name, 'Janis Joplin')
if __name__=='__main__':
    unittest.main()

就会显示测试失败。

11.1.4 测试未通过时怎么办

将name.py改为:

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

的这个新版本中,中间名是可选的。如果向这个函数传递了中间名(if middle: ),姓名将包含名、中间名和姓,否则姓名将只包含名和姓。 现在,对于两种不同的姓名,这个函数都应该能够正确地处理。

11.1.5 添加新测试
import unittest
from name import get_formatted_name
class NamesTestCase(unittest.TestCase):
    def test_first_last_name(self):
        formatted_name = get_formatted_name('janis', 'joplin')
        self.assertEqual(formatted_name, 'Janis Joplin')

    def test_first_last_middle_name(self):
        formatted_name = get_formatted_name('wolfgang', 'mozart', 'amadeus')
        self.assertEqual(formatted_name, 'Wolfgang Amadeus Mozart')
        
if __name__=='__main__':
    unittest.main()

在原来的代码中加入中间名字的检查便可以对两个都进行了测试。

11.2 测试类

很多程序中都会用到类,因此能够证明你的类能够正确地工作会大有裨益。如果针对类的测试通过 了,你就能确信对类所做的改进没有意外地破坏其原有的行为。

11.2.1 各种断言方法

Python在unittest.TestCase 类中提供了很多断言方法。

unittest Module中的断言方法:

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 中

11.2.2 一个要测试的类

suvery.py:

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('- ' + response)

language_survey.py:

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()
11.2.3 测试AnonymousSurvey 类
import unittest
from survey import AnonymousSurvey
class TestAnonmyousSurvey(unittest.TestCase):
    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()

在该代码中便测试了English是否在里面.

import unittest
from survey import AnonymousSurvey
class TestAnonmyousSurvey(unittest.TestCase):
    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.assertIn(response, my_survey.responses)
if __name__ == '__main__':
    unittest.main()

在该代码中核实用户提供三个答案时,它们也将被妥善地存储。

11.2.4 方法方法setUp()

unittest.TestCase 类包含方法setUp() ,让我们只需创建这些对象一次,并在每个测试方法中使用它们。如果你在TestCase 类中包含了方法setUp() ,Python将先运行它,再运行各个以test_打头的方法。这样,在你编写 的每个测试方法中都可使用在方法setUp() 中创建的对象了。

import unittest
from survey import AnonymousSurvey
class TestAnonmyousSurvey(unittest.TestCase):

    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() 做了两件事情:创建一个调查对象,创建一个答案列表。。存储这两样东西的变量名包含前缀self (即存储在属性中),因此可在这个类的任何 地方使用。这让两个测试方法都更简单,因为它们都不用创建调查对象和答案。方法test_store_three_response() 核实self.responses 中的第一个答案 ——self.responses[0] ——被妥善地存储,而方法test_store_three_response() 核实self.responses 中的全部三个答案都被妥善地存储

11.3 小结

在本章中,你学习了:如何使用模块unittest 中的工具来为函数和类编写测试;如何编写继承unittest.TestCase 的类,以及如何编写测试方法,以核实函数和类的行为 符合预期;如何使用方法setUp() 来根据类高效地创建实例并设置其属性,以便在类的所有测试方法中都可使用它们。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值