iTesting软件测试知识分享

测试框架--数据驱动动态增加测试用例

前面我们讲了什么是python数据驱动,如何使用及如何实现数据驱动。没看过文章的请移步:
Python数据驱动实践(一)–ddt实现数据驱动
Python数据驱动实践(二)–教你用Python实现数据驱动

今天我们来解决另外一个问题,实现数据驱动后,如何在测试报告里体现?

老规矩,先上段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 这段代码实现了一个事情, 测试一个sum_data的方法。
from functools import wraps
def data_provider(test_data):
def wrapper(func):
@wraps(func)
def repl(self, *args, **kwargs):
for i in test_data:
print('func starts')
func(self, *i, **kwargs)
print('func ends')
return repl
return wrapper
class SumData:
def __init__(self):
pass
def sum_data(self, *ags):
return sum(ags)
class TestSumData:
def __init__(self):
pass
@data_provider([(1, 2, 3), (4, 5, 9)])
def test_sum_data(self, x, y, z):
print("the value are {0}, {1}, {2}".format(x, y, z))
assert SumData().sum_data(x, y) == z
if __name__ == "__main__":
print(TestSumData().test_sum_data())
#唯一需要注意的是,@wraps的作用:
#由于装饰器的加入导致Python解释器认为函数本身发生了改变,所以用@wraps,
#它可以将原函数对象的指定属性复制给包装函数对象,保证装饰器不会对被装饰函数造成影响

我们知道,运行测试用例时候,通常会给一个待运行函数的集合,针对集合的每一个函数,逐个运行一遍,然后收集每个测试函数(用例)的名字,运行结果,然后保存,待生成测试报告用。

我们当前的代码, 根据data provider提供的数据不同,test_sum_data 这个函数也会运行多次,但是测试报告里只有一个test_sum_data, 那么如何解决呢?
1.先检查要运行的测试函数有没有data provider。
2.对于每个有data provider的测试函数,针对每一条数据,生成一个新的名字。
3.把新的名字加入到要运行的test case列表里。

根据这个我们知道,我们代码少两个函数实现, 一个是检查函数有没有data provider, 二是给有data provider装饰的函数生成新名字。怎么实现,当然是装饰器啦。
那么如何检查函数有没有提供data呢?我们可以人为给提供了data的函数加些属性。

1
2
3
4
5
6
7
def data_provider(test_data):
def wrapper(func):
setattr(func, "__data_Provider__", test_data)
global index_len
index_len = len(str(len(test_data)))
return func
return wrapper

如何给有__data__provider \ 属性的函数生成新名字呢?
1
2
3
4
def mk_test_name(name, value, index=0):
index = "{0:0{1}}".format(index+1, index_len)
test_name = "{0}_{1}_{2}".format(name, index, value)
return re.sub(r'\W|^(?=\d)', '_', test_name)

那么,怎么组织把这些命名的新函数添加到待运行列表呢?
1
2
3
4
5
6
7
8
def get_test_cases(cls):
return_cases = []
for name, func in list(cls.__dict__.items()):
if hasattr(func, '__data_Provider__'):
for i, v in enumerate(getattr(func, "__data_Provider__")):
test_name = mk_test_name(name, getattr(v, "__name__", v), i)
return_cases.append((test_name, func, v))
return return_cases

最后我们整理下,看看实际上是如何使用的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import re
def data_provider(test_data):
def wrapper(func):
setattr(func, "__data_Provider__", test_data)
global index_len
index_len = len(str(len(test_data)))
return func
return wrapper
class SumData:
def __init__(self):
pass
def sum_data(self, *ags):
return sum(ags)
class TestSumData:
def __init__(self):
pass
@data_provider([(1, 2, 3), (4, 5, 6)])
def test_sum_data(self, x, y, z):
print("the value are {0}, {1}, {2}".format(x, y, z))
assert SumData().sum_data(x, y) == z
def mk_test_name(name, value, index=0):
index = "{0:0{1}}".format(index+1, index_len)
test_name = "{0}_{1}_{2}".format(name, index, value)
return re.sub(r'\W|^(?=\d)', '_', test_name)
def get_test_cases(cls):
return_cases = []
for name, func in list(cls.__dict__.items()):
if hasattr(func, '__data_Provider__'):
for i, v in enumerate(getattr(func, "__data_Provider__")):
test_name = mk_test_name(name, getattr(v, "__name__", v), i)
return_cases.append((test_name, func, v))
return return_cases
if __name__ == "__main__":
cases_to_run = []
cases_run_success = []
cases_run_fail = []
#注1
cases_to_run = get_test_cases(TestSumData)
while cases_to_run:
try:
case = cases_to_run.pop(0)
name = case[0]
func = case[1]
v = case[2]
func(name, *v)
except:
# traceback.print_exc()
cases_run_fail.append(name)
else:
cases_run_success.append(name)
print(cases_run_success)
print(cases_run_fail)
#output
the value are 1, 2, 3
the value are 4, 5, 6
['test_sum_data_1__1__2__3_']
['test_sum_data_2__4__5__6_']

我们定义并维护了三个列表,一个是cases_to_run,放我们找到的所有的测试用例,一个是cases_run_success,放运行成功的用例,最后一个
cases_run_fail, 放测试不成功的用例。
从运行结果我们可以看出, 我们只有一个测试函数test_sum_data,测试报告里却有了两个用例test_sumdata112_3, test_sumdata245_6。

就这样我们就实现了测试报告里数据驱动可视化。

Hold on, 看我上面代码的注释(注1),我们传入的是固定的测试类,那么在真实的测试中,我希望框架去自动查找测试类和测试方法,这个怎么搞?
请期待下次分享 :)

🐶 您的支持将鼓励我继续创作 🐶
-------------评论, 吐槽, 学习交流,请关注微信公众号 iTesting-------------
iTesting wechat
扫码关注,跟作者互动

本文标题:测试框架--数据驱动动态增加测试用例

文章作者:iTesting

发布时间:2018年09月25日 - 23:09

最后更新:2018年12月28日 - 00:12

原始链接:http://www.helloqa.com/2018/09/25/测试框架/测试框架--数据驱动动态增加测试用例/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。