数据驱动测试
1. DDT 数据驱动测试基本介绍
DDT官方文档
DDT 数据驱动测试装饰器,可实现多个参数作用于一个测试用例,从而生成多个不同的子用例,需要搭配unittest 使用
使用ddt好处: 提高代码复用性、降低测试数据和代码耦合度、便于用例管理
ddt 核心的方法:
@data:包含与您想要传给测试用例的参数,一般是:字典、列表、元组等@file_data:将从JSON或YAML文件加载测试数据 (.yml和.yaml结尾的文件会被当做yaml文件加载,其余的都会以json文件加载)@unpack:通常data中的每个值将作为单个参数传递给测试方法。unpack会自动将元组和列表解压缩为多个参数,并将字典解压缩为多个关键字参数
2. @data使用示例
应用场景:测试过程相同,但随着参数的不同,预期结果不同,例如:
- 如同一个API,参数不同,响应数据也不一致
- 如登录显示菜单的功能,不同权限的用户登录,菜单展示的内容不同
2.1 元组
import unittest
from ddt import ddt, data, unpack, file_data
# 声明了ddt类装饰器@ddtclassMyddtTest(unittest.TestCase):defsetUp(self):print("setUp:每个用例执行前调用")deftearDown(self):print("tearDown:每个用例执行后调用")@data(1,2,3)deftest_01(self, value):# value用来接受data的数据print(value)if __name__ =="__main__":
unittest.main()
执行结果:
setUp:每个用例执行前调用
1
tearDown:每个用例执行后调用
setUp:每个用例执行前调用
2
tearDown:每个用例执行后调用
setUp:每个用例执行前调用
3
tearDown:每个用例执行后调用
示例说明:
- MyddtTest虽然只有一个
test_01,但是通过@data(1, 2, 3)分别将参数传递给test_01,test_01会执行三次,每次入参分别是1、2、3 setUp在每个测试用例执行前会自动执行、tearDown在每次测试用例执行后会自动执行,此处仅做打印,为了说明test_01被调用了三次
2.1 列表拆分&未拆分
import unittest
from ddt import ddt, data, unpack, file_data
# 声明了ddt类装饰器@ddtclassMyddtTest(unittest.TestCase):@data([4,5],[6,7],[9,10])deftest_02(self, value):print("test_02未拆分:",value)@data([4,5],[6,7],[9,10])@unpackdeftest_03(self, value1,value2):print("test_03已拆分:", value1,value2)if __name__ =="__main__":
unittest.main()
执行结果
test_02未拆分: [4, 5]
test_02未拆分: [6, 7]
test_02未拆分: [9, 10]
test_03已拆分: 4 5
test_03已拆分: 6 7
test_03已拆分: 9 10
示例说明:
test_02没有对数据拆分,因此入参是@data中可遍历的3组数据,因此test_02会执行3次test_03有对数据拆分,因此入参是@data中可遍历的3组数据,因此test_03会执行3次,因为使用了@unpack,每组还会被二次拆分
2.3 字典拆分&未拆分
import unittest
from ddt import ddt, data, unpack, file_data
# 声明了ddt类装饰器@ddtclassMyddtTest(unittest.TestCase):@data({'name':'zs','age':18},{'name':'ls','age':19})deftest_04(self, value):print("test_04未拆分:", value)@data({'name':'zs','age':18},{'name':'ls','age':19})@unpackdeftest_05(self, name,age):print("test_05已拆分:",f"name:{name},age:{age}")# test_06 与 test_05 用法等效,只是将数据存放在一个变量中# *testdata 在这里的作用是将 testdata 列表中的每个字典作为单独的参数传递给 data 装饰器。这使得 data 装饰器能够接收多个参数,而不是一个单一的列表参数。
testdata =[{'name':'zs','age':18},{'name':'ls','age':19}]@data(*testdata)@unpackdeftest_06(self, name, age):#字典拆分需要与key的个数对应,否则会报错print("test_06已拆分:",f"name:{name},age:{age}")if __name__ =="__main__":
unittest.main()
执行结果:
test_04未拆分: {'name': 'zs', 'age': 18}
test_04未拆分: {'name': 'ls', 'age': 19}
test_05已拆分: name:zs,age:18
test_05已拆分: name:ls,age:19
test_06已拆分: name:zs,age:18
test_06已拆分: name:ls,age:19
3. @file_data 使用示例
3.1 @file_data加载json文件
login_user.json
{
"user1": {
"name": "admin",
"password": "123456"
},
"user2": {
"name": "guest",
"password": "1122223"
}
}
MyddtTest.py
示例加载json文件并作用于testcase的两种方式
import unittest
from ddt import ddt, data, unpack, file_data
# 声明了ddt类装饰器@ddtclassMyddtTest(unittest.TestCase):@file_data("login_user.json")deftest_07(self, name, password):print("test_07:",f"name={name},password={password}")@file_data("login_user.json")deftest_08(self,**login_info):print("test_08:",f"name={login_info.get('name')},password={login_info.get('password')}")if __name__ =="__main__":
unittest.main()
执行结果: 可见两种写法效果是一样的
test_07: name=admin,password=123456
test_07: name=guest,password=1122223
test_08: name=admin,password=123456
test_08: name=guest,password=1122223
3.2 @file_data加载yaml文件
# config.yaml
# 使用-分隔用例,则yaml读取到的数据类型为列表
-
model: 登录模块
title: 登录成功
url: http://api.test.cn/api/user/user_login
method: POST
data:
username: admin
pwd: Ace123456
check:
error_code: 200
msg: 登录成功!
-
model: 登录模块
title: 密码错误
url: http://api.test.cn/api/user/user_login
method: POST
data:
username: admin
pwd: Ace123456!!
check:
error_code: 400
msg: 密码错误!
import unittest
from ddt import ddt, data, unpack, file_data
# 声明了ddt类装饰器@ddtclassMyddtTest(unittest.TestCase):# @file_data加载yaml文件@file_data("config.yaml")deftest_10(self, model, title, url, method, data, check):
username = data['username']
pwd = data['pwd']print(model, title, url, username, pwd, check)# **testdata:将提取到的数据存放在空字典testdata中@file_data("config.yaml")deftest_11(self,**testdata):# 再从字典testdata中单独提取参数
model = testdata['model']
title = testdata['title']
url = testdata['url']
username = testdata['data']['username']
pwd = testdata['data']['pwd']
check = testdata['check']print(model, title, url, username, pwd, check)if __name__ =="__main__":
unittest.main()
注:
使用ddt遇到的坑: 运行程序时将鼠标定位在类或者程序外运行解决,如果放在代码中间位置,如下代码,若鼠标放在第一行代码后面,点击
run
的时候会报错
type object 'MyddtTest' has no attribute 'test_04'
@data({'name':'zs','age':18},{'name':'ls','age':19})deftest_04(self, value):print("test_04未拆分:", value)
找到的原因是: 运行程序时将鼠标定位在类或者程序外运行解决,ddt只能运行整体,不能运行局部即单个测试方法
若有其他更合理的解释欢迎留言指导
版权归原作者 青格er 所有, 如有侵权,请联系我们删除。