unittest需要第三方插件ddt来实现数据驱动。数据可以是列表、字典或者JSON文件。
>pip install ddt进行安装
下面是一个简单的使用举例。
import unittest
import ddt
@ddt.ddt
class TestAdd(unittest.TestCase):
@ddt.data([1,2,3],[3,4,7])
@ddt.unpack
def test_add(self,a,b,c):
assert a+b==c
则分别使用提供的两组数据,执行两个test。
提供多少组数据,就创建多少个测试方法。这里创建的测试方法是test_add_1__1__2__3_ 和
test_add_2__3__4__7_ (__main__.TestAdd)。
@ddt.file_data('data.json')实现读取json数据,内容可以是列表或者字典。
excel数据驱动开发思路:
将读取出的excle文件中的数据以双重列表的方式返回,作为@ddt.data()的参数。
比如:实现一个函数,get_data_from_sheet(excel_file_path,sheet_name)。以双重列表的方式返回data。@ddt.data(*get_data_from_sheet(excel_file_path,sheet_name))使用数据。
ddt源代码分析:
下面以处理列表数据为例来分析,处理字典数据和json数据文件的主要流程是相同的。
ddt(arg=None, **kwargs)中对于每一组数据,执行test_name = mk_test_name(name,getattr(v, "__name__", v),i,fmt_test_name)构造新test函数的名字,其中name是原test函数的名字,v是一组数据,i是这组数据的index,fmt_test_name指定新的test函数的名字的格式。
然后执行add_test(cls,test_name,test_data_docstring,func,*v)基于原test函数func生成将新的test函数test_name,加入原testcase类cls,test_data_docstring 是新的test函数的docstring,v是对应的那组数据。
最后执行delattr(cls, name),删除原test函数。原test函数已经通过各组数据具体化成了新的test函数,所以已经不需要它了。留着它,执行时会抛出异常,TypeError: test_add() missing 3 required positional arguments: 'a', 'b', and 'c'。
下面来重点看一下生成新test函数的逻辑。
add_test(cls, test_name, test_docstring, func, *args, **kwargs)中setattr(cls, test_name, feed_data(func, test_name, test_docstring, *args, **kwargs))。
feed_data(func, new_name, test_data_docstring, *args, **kwargs)中
@wraps(func)
def wrapper(self):
return func(self, *args, **kwargs)
wrapper.__name__ = new_name
wrapper.__wrapped__ = func
wrapper.__doc__ = test_data_docstring
return wrapper
在原来的test函数func的基础上使用具体参数值,生成新的test函数,名字是new_name。然后将这个函数作为一个方法添加到原测试用例类cls中。
为了方便大家理解,下面我把生成新test函数的逻辑提取出来,写出下面的简化实现,以及对其使用的举例。
#下面两个函数生成新的test函数
def add_test(cls, test_name, func, *args):
setattr(cls, test_name, feed_data(func, test_name, *args))
def feed_data(func, new_name, *args):
def wrapper(self):
return func(self, *args)
wrapper.__name__ = new_name
return wrapper
#下面是使用举例
import unittest
class TestAdd(unittest.TestCase):
def test_add(self,a,b,c):
self.assertEqual(a+b,c)
add_test(TestAdd,"test_add_1_1_2_3",TestAdd.test_add,1,2,3)
add_test(TestAdd,"test_add_1_3_4_7",TestAdd.test_add,3,4,7)
delattr(TestAdd,"test_add")
unittest.main(verbosity=2)
'''
运行结果:
Total number of cases:2
test_add_1_1_2_3 (__main__.TestAdd) 1 ... ok
test_add_1_3_4_7 (__main__.TestAdd) 2 ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
'''