• 《Python编程从入门到实践》学习笔记10(第11章:测试函数)


      先说个题外话,第一个例子我用了差不多一个小时,才运出我想要的结果。对于一个菜鸟最烦的就是明明按照书上敲得一模一样,也不报错,就是运不出我想要的结果。菜鸟的学习果然是艰辛的,但我会坚持下去。这边我想说,我最终的解决方法是重启了我的编译器,然后然后然后,它就对了!所以我觉得我有时候真的太轴了,把代码敲了两遍,又不停地自己测试,最终还不如我朋友随嘴说的重开一下。。。不要轴,另辟蹊径,也许是康庄大道。

      笔者后面在做试一试的时候又碰到一样的问题:

      这次不像上次一样幸运,重启编译器两次,不行!复制了参考答案的代码,重新运行,不行!运行之前能运出来的程序,也不行了!重启电脑,还是不行!上网百度了一下,好多人好多说法,其中有一种让我成功运行了。如下图:

    上面一行不能省略,虽然我也不知道,我之前没有上面一行,只是重启了编译器怎么就能运行了。但是但是但是,后面想要继续运行就得这么干!

      

    11.1 测试函数

    11.1.1 单元测试四和测试用例

      Python标准库中的模块unittest提供了代码测试的工具。单元测试用于核实函数的某个方面没有问题;测试用例是一组单元测试,这些单元测试一起核实函数在各种情况下的行为都符合要求。全覆盖测试用例包含一整套单元测试,涵盖了各种可能的函数使用方式。

    11.1.2 可通过的测试

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

      下面是只包含一个方法的测试用例,它检查name_combine()在给定名和姓时能否正确地工作:

    import unittest
    from name import name_combine
    
    class NamesTestCase(unittest.TestCase):
    
        def test_names(self):
            """测试"""
            combined_name = name_combine('xiao','ming')
            self.assertEqual(combined_name,'Xiao Ming')
    
    unittest.main()

      测试结果:

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

      测试结果中的句点表明有一个测试通过。接下来的一行指出了Python运行了一个测试,消耗的时间不到0.001秒。最后的OK表明该测试用例中的所有单元测试都通过了。

     11.1.3 不能通过的测试

       如果将name.py 改成下面这样,这次运行程序test_name时,就会发现测试不能通过。

    E
    ======================================================================
    ERROR: test_names (__main__.NamesTestCase)
    测试
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "D:/PycharmProject/Study/test_name.py", line 8, in test_names
        combined_name = name_combine('xiao','ming')
    TypeError: name_combine() missing 1 required positional argument: 'last'
    
    ----------------------------------------------------------------------
    Ran 1 test in 0.000s
    
    FAILED (errors=1)

      第一行的E表示有一个单元测试导致了错误。接下来指出是NamesTestCase中的 test_names导致了错误。然后,一个标准的traceback指出函数调用name_combine('xiao','ming')有问题,少了一个参数。

    我们还看到运行了1个单元测试,最后还有一个消息,指出整个测试用例都未通过,因为该运行测试用例时发生了一个错误。

    11.1.4 测试未通过时怎么办

      如果你检查的条件没有错,测试通过了意味着函数的行为是对的,而测试未通过意味着你编写的新代码有错。因此,测试未通过时,不要修改测试,而应修复导致测试不能通过的代码:检查刚对函数所做的修改,找出导致函数行为不符合预期的修改。

      最佳的选择就是让中间名变成可选的:

      再次运行test_name.py:

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

    11.1.5 添加新的测试 

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

    import unittest
    from name import name_combine
    
    class NamesTestCase(unittest.TestCase):
    
        def test_names(self):
            """测试"""
            combined_name = name_combine('xiao','ming')
            self.assertEqual(combined_name,'Xiao Ming')
        
        def test_middle_name(self):
            """测试有中间名的名字"""
            combined_name = name_combine('xiao', 'ming','xiao')
            self.assertEqual(combined_name, 'Xiao Xiao Ming')
    unittest.main()

      测试结果:

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

       P192-193 动手试一试11-1、11-2 城市国家和人口数量

    city_funcition.py
    
    
    def city(cityname, countryname,population = ''):
        if population:
            city_country = cityname.title() + "," + countryname.title() + ' - population ' + str(population)
        else:
            city_country = cityname.title() + "," + countryname.title()
        return city_country
    

    test_cities.py
    import unittest from city_functions import city class CityTestCase(unittest.TestCase): """测试city_function""" def test_city_country(self): cityinfo = city('santiago', 'chile') self.assertEqual(cityinfo, 'Santiago,Chile') def test_city_country_pop(self): cityinfo = city('santiago', 'chile',5000000) self.assertEqual(cityinfo, 'Santiago,Chile - population 5000000') if __name__ =='__main__': unittest.main()

       测试结果:

    Ran 2 tests in 0.000s
    
    OK

    11.2 测试类 

    11.2.1 各种断言方法

      表11-1描述了6个常用的断言方法。使用这些方法可核实返回的值等于或不等于预期的值、返回的值为True或Flase、返回的值在列表中或不在列表中。只能在继承unittest.TestCase 的类中使用这些方法。

    表11-1 unittest Module中的断言方法
    self.assertEqual(a,b)
    self.assertNotEqual(a,b)
    self.assertTrue(x)
    self.assertFalse(x)
    self.assertIn(item,list)
    self.assertNotIn()

    11.2.2 一个要测试的类

      类的测试和函数的测试相似。

      创建一个匿名调查的类:

    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 result:")
            for response in self.responses:
                print('-' + response)

      测试 AnonymousSurvey()类:

    import unittest
    from survey import AnonymousSurvey
    
    class SurveyTestCase(unittest.TestCase):
        """测试匿名调查类"""
    
        def test_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_three_response(self):
            """测试三个答案会被妥善处理"""
            question = "What language did you first learn to speak"
            my_survey = AnonymousSurvey(question)
            responses = ['English','Spanish','Chinese']
            for response in responses:
                my_survey.store_response(response)
    
            for response in responses:
                self.assertIn(response,my_survey.responses)
    
    if __name__ =='__main__':
        unittest.main()

      测试结果:

    Ran 2 tests in 0.000s
    
    Launching unittests with arguments python -m unittest D:/PycharmProject/Study/test_aurvey.py in D:PycharmProjectStudy
    OK

    11.2.3 方法setUp()

       在上面的实例中,我们在每个测试方法中都创建了一个AnonymousSurvey()实例,并在每个方法中都创建了答案。unittest.TestCase类包含setUp()方法,Python将先运行它,再运行各个以test_打头的方法。这样,在你编写的每个测试方法中都可以使用在方法setUp()中创建的对象了。

      下面用setUp()来创建一个调查对象和一组答案,供test_three_response()、test_single_response()使用:

    import unittest
    from survey import AnonymousSurvey
    
    class SurveyTestCase(unittest.TestCase):
        """测试匿名调查类"""
    
        def setUp(self):
            """
            创建一个调查对象和一组答案,供使用的测试方法使用
            """
            question = "What language did you first learn to speak?"
            self.my_survey = AnonymousSurvey(question)
            self.responses = ['English', 'Spanish', 'Chinese']
    
        def test_single_response(self):
            """测试单个答案会被妥善地存储"""
            self.my_survey.store_response(self.responses[0])
            self.assertIn(self.responses[0],self.my_survey.responses)
    
        def test_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)
    
    if __name__ =='__main__':
        unittest.main()

       setUp()方法做了两件事:创建一个调查对象;创建一个答案列表。存储这两样东西的变量名包含前缀self(即存储在属性中),因此可在这个类的任何地方使用。这让两个测试方法都更简单,因为它们都不用创建调查对象和答案。再次运行时,这两个测试都通过了。

      p198动手试一试11-3雇员

      创建Employee类

    class Employee():
        def __init__(self,firstname,lastname,wage):
            self.firstname = firstname
            self.lastname = lastname
            self.wage = wage
    
        def give_raise(self,increase = 5000):
            self.wage += increase

      测试Employee类:

    import unittest
    from employee import Employee
    
    class EmployeeTestCase(unittest.TestCase):
        """测试Employee类"""
    
        def setUp(self):
            """创建一个employee对象"""
            self.employee = Employee(firstname='xiao',lastname='ming',wage=1000)
    
        def test_give_default_raise(self):
            """薪资默认上升值为5000"""
            self.employee.give_raise()
            self.assertEqual(self.employee.wage,6000)
    
        def test_give_custom_raise(self):
            """薪资上升值设置为9000"""
            self.employee.give_raise(9000)
            self.assertEqual(self.employee.wage,10000)

      测试结果:

    Ran 2 tests in 0.001s
    
    OK
  • 相关阅读:
    EasyUI限制时间选择(开始时间小于结束时间)
    C# readonly与const的区别
    C# Lambda 表达式
    C# 扩展方法
    C# 枚举enum
    Visual Studio中的“build”、“rebuild”、“clean”的区别
    无root开热点教程
    数据库锁
    安卓:标题栏右上角添加按钮
    安卓:从assets目录下复制文件到指定目录
  • 原文地址:https://www.cnblogs.com/cathycheng/p/11212541.html
Copyright © 2020-2023  润新知