测试代码模块
编写函数或类时,还可为其编写测试。通过测试,可确定代码面对各种输入都能够按要求的那样工作。在程序中添加新代码时,你也可以对其进行测试,确认它们不会破坏程序既有的行为。
使用Python模块unittest 中的工具来测试代码
【注意】:测试代码所在的类,必须继承unittest.TestCase继承类
(1)单元测试与测试用例
Python标准库中的模块unittest提供了代码测试工具。
1、单元测试用于核实函数的某个方面没有问题;
2、测试用例是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求。
良好的测试用例考虑到了函数可能收到的各种输入,包含针对所有这些情形的测试。
3、全覆盖式测试用例包含一整套单元测试,涵盖了各种可能的函数使用方式。
对于大型项目,要实现全覆盖可能很难。通常,最初只要针对代码的重要行为编写测试即可,等项目被广泛使用时再考虑全覆盖。(一般都做不到)
(2)可通过的测试
创建测试用例的语法需要一段时间才能习惯,但测试用例创建后,再添加针对函数的单元测试就很简单了。
【编写函数测试模块语法】:
要为函数编写测试用例,可先导入模块unittest 以及要测试的函数,再创建一个继承unittest.TestCase 的类,并编写一系列方法对函数行为的不同方面进行测试。
import unittest #导入测试模块
from name_function import get_formatted_name
class NamesTestCase(unittest.TestCase): #必须继承unittest.TestCase类
"""测试name_function.py"""
def test_first_last_name(self): # 所有以test打头的方法都将被Python自动执行(测试类中,继承unittest.TestCase的类表示测试类)
"""能够正确地处理像Janis Joplin这样的姓名吗?"""
formatted_name = get_formatted_name('janis', 'joplin')#需测试的函数(自定义函数)得到的结果
self.assertEqual(formatted_name, 'Janis Joplin') #调用unittest 的方法assertEqual() 断言方法
#将自己的函数得出的解果与正确结果进行比较,若正确,则输出ok,反之输出error
unittest.main()#运行测试代码
(3)断言方法
使用了unittest 类最有用的功能之一:一个断言方法。断言方法用来核实得到的结果是否与期望的结果一致,即检查你认为应该满足的条件是否确实满足。
例如:
self.assertEqual(formatted_name, ‘Janis Joplin’)
我们调用unittest 的方法assertEqual() ,并向它传递formatted_name 和’Janis Joplin’ 。代码行self.assertEqual(formatted_name, ‘Janis Joplin’) 的意思是 说:“将formatted_name 的值同字符串’Janis Joplin’ 进行比较。
(4)重复进行测试
修改自己的函数,既可实现重复测试
(5)运行测试文件
代码行unittest.main()让Python运行这个文件中的测试代码。
A、通过测试结果如下:
. #句点代表有一个测试通过了 n个点,代表n个测试通过
----------------------------------------------------------------------
Ran 1 test in 0.000s #表示Python运行了一个测试。消耗时间不到0.001秒
OK #表示该测试案例中所有的单元测试都通过了
B、不能通过的测试结果如下:
E #输出只有一个字母E,表示测试用例中只有一个单元测试导致了错误。 即出现n个字母E,即有n个单测试导致了错误
======================================================================
ERROR: test_first_last_name (__main__.NamesTestCase) #错误位置 NamesTestCase 中的test_first_last_name() 导致了错误
----------------------------------------------------------------------
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) #指出整个测试用例都未通过 因为运行该测试用例时发生了一个错误
#这条消息位于输出末尾,让你一眼就能看到
(6)测试未通过则么办?
如果你检查的条件没错,测试通过了意味着函数的行为是对的,而测试未通过意味着你编写的新代码有错。因此,测试未通过时,不要修改测试,而应修复导致测试不能通过的代码:检查刚对函数所做的修改,找出导致函数行为不符合预期的修改。
(7)添加新测试函数
可根据具体的项目开发需求,编写多个测试函数,进行方法测试
(8)类测试
前面主要介绍了针对单个函数的测试,下面来编写针对类的测试。很多程序中都会用到类,因此能够证明你的类能够正确地工作会大有裨益。如果针对类的测试通过 了,你就能确信对类所做的改进没有意外地破坏其原有的行为。
A、常见断言方法: 必须在unittest类中使用,所以必须继承
Python在unittest.TestCase 类中提供了很多断言方法。前面说过,断言方法检查你认为应该满足的条件是否确实满足。如果该条件确实满足,你对程序行为的假设就得到了 确认,你就可以确信其中没有错误。如果你认为应该满足的条件实际上并不满足,Python将引发异常。
上表中主要举例的方法,必须在unittest.TestCase类中使用
B、测试类的实现
类的测试与函数的测试相似——你所做的大部分工作都是测试类中方法的行为,但存在一些不同之处。
import unittest #导入测试模块
from survey import AnonymousSurvey
class TestAnonmyousSurvey(unittest.TestCase): #必须继承unittest.TestCase类
"""针对AnonymousSurvey类的测试"""
def test_store_single_response(self):#test开头 自动运行
"""测试单个答案会被妥善地存储"""
question = "What language did you first learn to speak?"
my_survey = AnonymousSurvey(question)
my_survey.store_response('English')
self.assertIn('English', my_survey.responses) #断言方法 核实item是否在list中 返回true or false
unittest.main()#测试函数启动
【小tips】:
类测试和函数测试主要过程是一样的,类测试是通过测试类中的每一个函数,进行类中每一个方法的测试,来实现最终的类测试。
在调用方法时,需先对类进行实例化,然后通过实例化的对象调用类中的方法,进行测试。
(9)方法setUp()
unittest.TestCase 类包含方法setUp(),让我们只需创建这些对象一次,并在每个测试方法中使用它们。如果你在TestCase 类中包含了方法setUp() ,Python将先运行它,再运行各个以test_打头的方法。
重写unittest.TestCase类(父类)中的setUp() 函数,在该函数中创建对象。使用setup()函数,可以简化创建对象的步骤,在每次运行测试代码时,Python将最先运行setup()函数,然后再运行各个test_打头的方法。
【优势】:
测试自己编写的类时,方法setUp() 让测试方法编写起来更容易:可在setUp() 方法中创建一系列实例并设置它们的属性,再在测试方法中直接使用这些实例。相比于在每个 测试方法中都创建实例并设置其属性,这要容易得多。