《Python编程从入门到实践》第十一章

在本章中,你将学习如何使用Python模块unittest中的工具来测 试代码。

测试函数

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

"""name_function.py"""
def get_formatted_name(first, last):
    full_name = first + ' ' + last
    return full_name.title()
'''names.py'''
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':
        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 + '.')
'''test_name_function.py'''
import unittest
from name_function import get_formatted_name

class NameTestCase(unittest.TestCase):
    def test_first_last_name(self):
        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才知道如何运行你编写的测试。 NamesTestCase只包含一个方法,用于测试get_formatted_name()的一个方面。我们将这个方 法命名为test_first_last_name(),因为我们要核实的是只有名和姓的姓名能否被正确地格式化。 我们运行test_name_function.py时,所有以test_打头的方法都将自动运行。在这个方法中,我们调用了要测试的函数,并存储了要测试的返回值。在这个示例中,我们使用实参'janis'和'joplin' 调用get_formatted_name(),并将结果存储到变量formatted_name中。
另外,上例中使用了一个断言方法,代码行self.assertEqual(formatted_name, 'Janis Joplin')的意思是说: 将formatted_name的值同字符串'Janis Joplin'进行比较,判断是否相等。代码行unittest.main()让Python运行这个文件中的测试。

测试类

unnittest Module中的断言方法.png

测试过程类似于对函数的测试:

'''survey.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()
'''test_survey.py'''
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)

unittest.main()

方法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)

unittest.main()

方法setUp()做了两件事情:创建一个调查对象;创建一个答案列表。存储这 两样东西的变量名包含前缀self(即存储在属性中),因此可在这个类的任何地方使用。这让两 个测试方法都更简单,因为它们都不用创建调查对象和答案。方法test_store_three_response() 核实self.responses中的第一个答案——self.responses[0]——被妥善地存储,而方法 test_store_three_response()核实self.responses中的全部三个答案都被妥善地存储。
运行测试用例时,每完成一个单元测试,Python都打印一个字符:测试通过时打印一个 句点;测试引发错误时打印一个E;测试导致断言失败时打印一个F。这就是你运行测试 用例时,在输出的第一行中看到的句点和字符数量各不相同的原因。如果测试用例包含 很多单元测试,需要运行很长时间,就可通过观察这些结果来获悉有多少个测试通过了。

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

你可能感兴趣的:(《Python编程从入门到实践》第十一章)