• python-测试代码


    介绍

    在本章中你会学习如何使用Python模块nuittest中的工具来测试代码。你将了解测试通过和未通过的样子;同时,你将学习如何测试函数和类;和知道该为项目编写多少个测试。

    测试函数

    要学习测试,先得有测试的代码。下面编写了一个简单的函数,它接受名和姓并返回整洁的姓名。

    name_function.py
    
    def get_formatted_name(first,last):
        full_name=first+' '+last
        return full_name.title()
    
    • 1
    • 2
    • 3
    • 4
    • 5

    为核实get_formatted_name()像期望那样工作,我们来编写一个使用这个函数的程序。程序names.py让用户输入名和姓,并显示整洁的全名。

    names.py
    from name_function import get_formatted_name
    print("Enter 'q' at any time to quit.")
    while True:
        first = input("please input your first name:")
        if first == 'q':
            break
        last = input("please input your last name:")
        if last == 'q':
            break
        formatted_name=get_formatted_name(first,last)
        print("\tNeatly formatted name:"+formatted_name+'.')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    单元测试和测试用例

    python标注库中的模块nuittest提供了代码测试工具。
    良好的测试用例考虑到了函数可能收到的各种输入,包含针对所有这些情形的测试。
    单元测试用于核实函数某个方面没有问题
    测试用例是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求。
    全覆盖测试用例包含一整套单元测试,涵盖了各种可能的函数使用方式。

    可通过的测试

    要为函数编写测试用例,可先导入模块unittest以及要测试的函数,再创建一个继承unittest.TestCase的类,并编写一系列方法对函数行为的不同方面进行测试。
    下面是一个只包含一个方法的测试用例,它检查函数get_formatted_name()在给定名和姓时是否正确地工作。

    test_name_function.py
    
    import unittest
    from name_function 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') #3
    
    unittest.main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    解释:类nameTestCase继承了unittest.TestCase类。
    3处我们使用了unittest类最有用的功能之一:一个断言方法,断言方法用来核实得到的结果是否与预期的结果一致。比较fomatted_name的值和字符串’janis joplin’,如果他们相等,就万事大吉,如果他们不相等就跟我说一声。
    结果出现句点和OK,表示测试通过了。

    不能通过的测试

    在name_function.py中添加一个名为new_get_formatted_name(first,middle,last)的函数,添加一个中间名。再放到test_name_function.py中测试:self.assertEqual(formatted_name, ‘janis joplin’),测试代码只改变为新的函数,其余不变。

    E ❶
    ======================================================================
    ERROR: test_first_last_name (__main__.NamesTestCase)----------------------------------------------------------------------
    Traceback (most recent call last): ❸
      File "test_name_function.py", line 8, in test_first_last_name
        formatted_name = get_formatted_name('janis', 'joplin')
    TypeError: get_formatted_name() missing 1 required positional argument: 'last'
    ----------------------------------------------------------------------
    Ran 1 test in 0.000s ❹
    FAILED (errors=1)
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    报错:

    1. 第一行只输出一个字母E,他指出测试用例中有一个单元测试导致了错误。
    2. ②处表示为:NamesTestCase中的test_first_last_name()导致了错误。测试用例中包含从多单元测试时,知道那个测试未通过至关重要。
    3. 在③处,它指出函数get_formatted_name(‘janis’,‘joplin’)有问题,因为它缺少一个必不可少的位置实参。
    4. 第④处,我们可以看到运行了一个单元测试。
    5. 第⑤处,我们可以知道测试该用例一共有几个错误。

    测试未通过时怎么办

    如果你检查的条件没有错,测试通过了意味着函数的行为是对的,而测试没有通过意味着你编写的新代码有错。因此,测试未通过时,不要修改测试,而应修复导致测试不能通过的代码。
    在这个示例中,get_formatted_name()以前只需要两个实参–姓和名,但现在它要求提供中间名。新增的中间名参数是必不可少的,这导致get_formatted_name()的行为不符合预期。故最佳选择为让中间名变为可选的。

    name_function.py
    
    def new_get_formatted_name(first, last, middle=''):
        if middle:
            full_name = first + ' ' + middle + ' ' + last
            return full_name
        else:
            full_name = first + ' ' + last
            return full_name
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    再进行测试,测试通过。

    添加新测试

    确定get_formatted_name()又能正确地处理简单的姓名后,我们再编写一个测试。用于测试包含中间名的姓名。
    为此,我们在NamesTestCase类中再添加一个方法。

    import unittest
    from name_function import new_get_formatted_name
    
    
    class NamesTestCase(unittest.TestCase):
        def test_first_last_name(self):
            formatted_name = new_get_formatted_name('janis', 'joplin')
            self.assertEqual(formatted_name, 'janis joplin')
    
        def test_first_last_middle_name(self):
            formatted_name = new_get_formatted_name('wolfgang','mozart','amadeus')
            self.assertEqual(formatted_name, 'wolfgang amadeus mozart')
    
    
    unittest.main()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    补充:我们把这个方法命名为test_first_last_middle_name()。方法名必须以test_打头,这样它才会在我们运行test_name_function.py时自动运行。
    在TestCase类中,使用很长的方法名是可以的,这些方法名称必须是描述性的,这样才能让你明白测试未通过时的输出。
    这些方法由python调用,不用你编写他们的代码。

    测试类

    各种断言方法

    python在unittest.TestCase类中提供了很多断言的方法。前面说过,断言方法检查你认为应该满足的条件是否可以满足。如果该条件满足,你对程序的假设就得了确认,你就可以确信其中没有错误。如果你认为应该满足的条件实际并不满足,python将引发异常。
    常见的断言方法有六个:

    方法用途
    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 中

    一个要测试的类

    下面来编写一个类进行测试,创建一个帮助管理匿名调查的类。

    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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    编写一个使用该类的程序

    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
        else:
            my_survey.store_response(response)
    print("\nThank you to everyone who participated in the survey!")
    my_survey.show_results()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    测试AnonymousSurvey类

    编写一个测试,对AnonymousSurvey类的行为的一个方面进行验证:如果用户面对调查问题时只提供了一个答案,这个答案也能被妥善地存储。为此,我们将在这个答案被存储后,使用方法assertln()来核实它包含在答案列表中:

    test_survey.py
    
    import unittest
    from survey import AnonymousSurvey
    
    
    class TestAnonymousSurvey(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)
    
    
    unittest.main()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    测试成功,但它只能收集一个答案的调查用途不大。下面来核实用户提供三个答案时,他们也将被妥善地存储。故,我们在TestAnonymousSurvey中添加一个方法。

    import unittest
    from survey import AnonymousSurvey
    
    
    class TestAnonymousSurvey(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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    方法setUp()

    前面的测试效果很好,但有些测试有重复的地方,接下来使用unittest的另一项功能来提高它们的效率。
    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):
        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_response(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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    解释:方法setUp()做了两件事:创建一个调查对象;创建一个答案列表。存储这两样东西的变量名包含前缀self(即存储在属性中),因此可在这个类的任何地方使用。这让两个测试方法都更简单,因为它们都不用创建调查对象和答案。
    方法setUp()让测试方法编写起来更容易:可在setUp()方法中创建一系列实例并设置它们的属性,再在测试方法中直接使用这些实例。

  • 相关阅读:
    简单了解CyclicBarrier
    权威认证!瀚高股份IvorySQL通过强制性国标GB18030-2022最高级别认证
    java计算机毕业设计英语网站源程序+mysql+系统+lw文档+远程调试
    Apple硬件相关
    目标检测算法——YOLOv5/YOLOv7改进结合新神经网络算子Involution(CVPR 2021)
    渔业安全生产综合管理指挥系统-航迹数据优化方案
    java学习笔记第一天
    导师邀请你继续跟他读博,你会不会立马答应?
    2021年华数杯数学建模A题电动汽车无线充电优化匹配研究求解全过程文档及程序
    设计模式-工厂模式
  • 原文地址:https://blog.csdn.net/m0_61786761/article/details/126802244