测试是用来确定代码在面对各种输入时能按照要求进行工作,提前测试有利于防止新代码不会破坏程序既有的行为,本章使用unittest中的工具,编写测试用例,核实输入将得到的输出
formatted 格式化 Generate生成 neatly 整洁的 full完全的
1 from name_function import get_formatted_name #从name_function.py中导入get_formatted_name()
11-1城市和国家:编写一个函数,它接受两个形参:一个城市名和一个国家名。这个函数返回一个格式为City, Country的字符串,如Santiago, Chile。将这个函数存储在一个名为city _functions.py的模块中。创建一个名为test_cities.py的程序,对刚编写的函数进行测试(别忘了,你需要导入模块unittest以及要测试的函数)。编写一个名为test_city_country()的方法,核实使用类似于'santiago'和'chile'这样的值来调用前述函数时,得到的字符串是正确的。运行test_cities.py,确认测试test_city_country()通过了。
1 #city_functions.py 2 def city_country(city_name, country_name, middle=','): # 3 """输出城市名和国家名,例如Santiago, chile""" 4 full_city_country = city_name + middle + country_name 5 return full_city_country.title() 6 7 #city_name_country_name.py 8 from city_functions import city_country 9 print("Enter 'q' at any time to quit.") 10 while True: 11 city_name = input("亲输入城市名: ") 12 if city_name == 'q': 13 break 14 country_name = input("亲输入国家名: ") 15 if country_name == 'q': 16 break 17 18 formatted_name = city_country(city_name, country_name) 19 print("\n城市和国家名的输出结果: " + formatted_name) 20 21 22 #test_cityname_and_country_name.py 23 import unittest #导入inttest模块中的工具 24 from city_functions import city_country 25 26 class NamesTestCase(unittest.TestCase): #这个命名可以随意,但通常都与测试的函数相关而且要包含Test字样 27 """测试city_functions.py""" #继承TestCase类这样Python才知道如何运行你编写的测试,可以认为是一个接口将你的函数 28 #在另一个地方运行 29 def test_city_country_name(self): #这个测试文件的方法要用test_为开头,_test为开头的方法在文件运行时会自动运行 30 """能够正确地处理像Santigo, Chile这类的名字吗?""" 31 formatted_name = city_country('Santigo', 'Chile') #调用了要测试的函数,并将返回值储存到formatted_name中 32 self.assertEqual(formatted_name, 'Santigo,Chile')#使用断言方法assertEqual用来核实得到的结果是否与期望的结果一致 33 34 '''在这里,我们知道get_formatted_name()应返回这样的城市国家名,即 35 首字母为大写,且它们之间有一个‘,’,因此我们期望formatted_name的值为Santigo,Chile。为检查是否确实如此,我们调用unittest的方法assertEqual(),并向它传递formatted_ 36 name和'Santigo Chile'。代码行self.assertEqual(formatted_name, 'Janis Joplin')的意思是说:“将formatted_name的值同字符串'Santigo,Chile'进行比较,如果它们相等,就万事大吉,如果它 37 们不相等,跟我说一声!''' 38 unittest.main()
11-2人口数量:修改前面的函数,使其包含第三个必不可少的形参population,并返回一个格式为City, Country – population xxx的字符串,如Santiago, Chile –population 5000000。运行test_cities.py,确认测试test_city_country()未通过。修改上述函数,将形参population设置为可选的。再次运行test_cities.py,确认测试test_city_country()又通过了。再编写一个名为test_city_country_population()的测试,核实可以使用类似于'santiago'、'chile'和'population=5000000'这 样 的 值 来 调 用 这 个 函 数 。 再 次 运 行test_cities.py,确认测试test_city_country_population()通过了。
1 #写到一般才看到是测试两个。。一个可选,一个不可选 2 #不可选 3 def city_country_population(city_name, country_name, population='population-50000'): 4 """输出城市名和国家名,例如Santiago, chile""" 5 full_city_country = (city_name + ', ' + 6 country_name + str(population)) 7 return full_city_country.title() 8 #city_country_population_name.py 9 from city_country_population import city_country_population 10 population = 'population-500000' 11 print("Enter 'q' at any time to quit.") 12 while True: 13 city_name = input("亲输入城市名: ") 14 if city_name == 'q': 15 break 16 country_name = input("亲输入国家名: ") 17 if country_name == 'q': 18 break 19 #population = input("请输入人口数: ") 20 #if population == 'q': 21 #break 22 23 formatted_name = city_country_population(city_name, country_name, population) 24 print("\n城市和国家名和人口的输出结果: " + formatted_name) 25 #可选 26 #city_country_population.py 27 def city_country_population(city_name, country_name, population): 28 """输出城市名和国家名,例如Santiago, chile""" 29 full_city_country = (city_name + ', ' + 30 country_name + ' -population ' + population) 31 return full_city_country.title() 32 33 #city_country_population_name.py 34 from city_country_population import city_country_population 35 print("Enter 'q' at any time to quit.") 36 while True: 37 city_name = input("亲输入城市名: ") 38 if city_name == 'q': 39 break 40 country_name = input("亲输入国家名: ") 41 if country_name == 'q': 42 break 43 population = input("请输入人口数: ") 44 if population == 'q': 45 break 46 47 formatted_name = city_country_population(city_name, country_name, population) 48 print("\n城市和国家名和人口的输出结果: " + formatted_name) 49 50 #test_city_and_country_populations.py 51 import unittest 52 from city_country_population import city_country_population 53 54 class NamesTestCase(unittest.TestCase): 55 """测试city_functions.py""" 56 57 def test_city_country_population_name(self): 58 """能够正确地处理像Santigo, Chile这类的名字吗?""" 59 formatted_name = city_country_population('Asd', 'Asd', '456') 60 self.assertEqual(formatted_name, 'Asd, Asd -Population 456') 61 62 unittest.main() 63 #测试不通过的没写,因为太多不通过的方法了,没有明确定义用啥
断言方法
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-3雇员:编写一个名为Employee的类,其方法__init__()接受名、姓和年薪,并将它们都存储在属性中。编写一个名为give_raise()的方法,它默认将年薪增加5000美元,但也能够接受其他的年薪增加量。为Employee编写一个测试用例,其中包含两个测试方法:test_give_default_raise()和test_give_custom_raise()。使用方法setUp(),以免在每个测试方法中都创建新的雇员实例。运行这个测试用例,确认两个测试都通过了。
1 #Employee.py 2 class Employee: 3 """收集打工人的信息""" 4 def __init__(self, firstname, lastname, money): 5 """打工人初始化""" 6 self.firstname = firstname 7 self.lastname = lastname 8 self.money = money 9 def give_raise(self, addmoney=5000): 10 """应该加的钱(可能吗)""" 11 self.money += addmoney 12 13 #测试用例 14 import inttest 15 from Employee import Employee #文件Employee内的Employee类 16 class EmployeeTestCase(unittest.TestCase): #如果你在TestCase类中包含了方法setUp(),Python将先运行 17 # 它,再运行各个以test_打头的方法 18 """测试不同打工人的信息""" 19 def setUp(self): 20 """初始化打工人信息""" #方法setUp(),让我们只需创建这些对象一 21 # 次,并在每个测试方法中使用它们。 22 self.default = Employee('xiao', 'ma', 1000) #变量名包含前缀self(即存储在属性中) 23 """默认加的薪水""" 24 self.default.give_raise() 25 self.assertEqual(self.default.money,6000) 26 def test_igive_coustom_raise(self): 27 """特殊加薪""" 28 self.default.give_raise(8000) 29 self.assertEqual(self.default.money,9000) 30 unittest.main()
小结:测试代码
参与工作量较大的项目时,你应对自己编写的函数和类的重要行为进行测试,在项目早期,不要试图去编写全覆盖的测试用例,除非有充分的理由这样做。
使用模块unittest中的工具来为函数和类编写测试;如何编写继承unittest.TestCase的类,以及如何编写测试方法,以核实函数和类的行为符合预期;如何使用方法setUp()来根据类高效地创建实例并设置其属性,以便在类的所有测试方法中都可使用它们。