12-Unittest和Pytest参数化详解

  • 1 Unittest参数化
    • 1.1 ddt
      • 1.1.1 简介
      • 1.1.2 说明
      • 1.1.3 安装
      • 1.1.4 版本信息
      • 1.1.5 实例1
      • 1.1.6 实例2
    • 1.2 paramunittest
      • 1.2.1 说明
      • 1.2.2 安装
      • 1.2.3 版本信息
      • 1.2.3 实例:参数传入元组数据
      • 1.2.4 实例:参数传入列表数据
      • 1.2.5 实例:参数传入字典数据
      • 1.2.6 实例:参数传入对象
      • 1.2.7 实例:参数传入函数
      • 1.2.8 实例:通过继承unittest.TestCase类执行案例
  • 2 Pytest参数化
    • 2.1 说明
    • 2.2 parametrize方法
      • 2.2.1 参数说明
      • 2.2.2使用参数化前后比对
        • 2.2.2.1 使用前
        • 2.2.2.2 使用后
    • 2.3 常用场景
      • 2.3.1 装饰测试类
      • 2.3.2 “笛卡尔积”,多个参数化装饰器
      • 2.3.3 参数化传入字典数据
      • 2.3.4 参数化标记数据
      • 2.3.5 参数化增加可读性

1 Unittest参数化

1.1 ddt

1.1.1 简介

  • 数据驱动ddt可以实现测试数据与测试脚本的分离;
  • 通过ddt来将测试数据加载到脚本中;

1.1.2 说明

  • 测试数据为嵌套字典的列表;
  • 测试类前加修饰@ddt
  • 测试用例前加修饰@data()
  • 运行后用例会自动加载成多个单独的用例。

1.1.3 安装

pip install ddt

1.1.4 版本信息

C:\Users\Administrator>pip show ddt
Name: ddt
Version: 1.4.2
Summary: Data-Driven/Decorated Tests
Home-page: https://github.com/datadriventests/ddt
Author: Carles Barrobés
Author-email: carles@barrobes.com
License: UNKNOWN
Location: d:\python37\lib\site-packages
Requires:
Required-by:

1.1.5 实例1

# -*- coding:utf-8 -*-
# 作者:NoamaNelson
# 日期:2022/11/21
# 文件名称:test_unittest_ddt.py
# 作用:unittest数据驱动ddt
# 联系:VX(NoamaNelson)
# 博客:https://blog.csdn.net/NoamaNelsonimport unittest
from ddt import *test_case = [{"data": {"name": "NoamaNelson", "pwd": "123456"}, "info": {"msg": "登陆成功", "code": "200"}},{"data": {"name": "noama", "pwd": "123456"}, "info": {"msg": "登陆失败,用户名或密码错误!", "code": "201"}},{"data": {"name": "", "pwd": "123456"}, "info": {"msg": "用户名不能为空!", "code": "201"}},{"data": {"name": "NoamaNelson", "pwd": ""}, "info": {"msg": "密码不能为空!", "code": "201"}},{"data": {"name": "", "pwd": ""}, "info": {"msg": "用户名和密码不能为空!", "code": "201"}}]@ddt
class TestCase(unittest.TestCase):@classmethoddef setUpClass(cls) -> None:print("打开浏览器进入登陆界面")@classmethoddef tearDownClass(cls) -> None:print("关闭退出浏览器")def login(self, name, pwd):if name == "NoamaNelson" and pwd == "123456":return {"msg": "登陆成功", "code": "200"}elif name == "noama" and pwd == "123456":return {"msg": "登陆失败,用户名或密码错误!", "code": "201"}elif name == "" and pwd == "123456":return {"msg": "用户名不能为空!", "code": "201"}elif name == "NoamaNelson" and pwd == "":return {"msg": "密码不能为空!", "code": "201"}elif name == "" and pwd == "":return {"msg": "用户名和密码不能为空!", "code": "201"}else:return False@data(*test_case)def test_case_data(self, case):print(f"case:{case}")print(f"case[info]:{case['info']}")print(f"返回值为:{self.login(case['data']['name'], case['data']['pwd'])}")self.assertEqual(case['info'], self.login(case['data']['name'], case['data']['pwd']))if __name__ == '__main__':unittest.main()
test_unittest_ddt.py::TestCase::test_case_data_1 打开浏览器进入登陆界面
PASSED
[ 20%]case:{'data': {'name': 'NoamaNelson', 'pwd': '123456'}, 'info': {'msg': '登陆成功', 'code': '200'}}
case[info]:{'msg': '登陆成功', 'code': '200'}
返回值为:{'msg': '登陆成功', 'code': '200'}test_unittest_ddt.py::TestCase::test_case_data_2 PASSED
[ 40%]case:{'data': {'name': 'noama', 'pwd': '123456'}, 'info': {'msg': '登陆失败,用户名或密码错误!', 'code': '201'}}
case[info]:{'msg': '登陆失败,用户名或密码错误!', 'code': '201'}
返回值为:{'msg': '登陆失败,用户名或密码错误!', 'code': '201'}test_unittest_ddt.py::TestCase::test_case_data_3 PASSED
[ 60%]case:{'data': {'name': '', 'pwd': '123456'}, 'info': {'msg': '用户名不能为空!', 'code': '201'}}
case[info]:{'msg': '用户名不能为空!', 'code': '201'}
返回值为:{'msg': '用户名不能为空!', 'code': '201'}test_unittest_ddt.py::TestCase::test_case_data_4 PASSED
[ 80%]case:{'data': {'name': 'NoamaNelson', 'pwd': ''}, 'info': {'msg': '密码不能为空!', 'code': '201'}}
case[info]:{'msg': '密码不能为空!', 'code': '201'}
返回值为:{'msg': '密码不能为空!', 'code': '201'}test_unittest_ddt.py::TestCase::test_case_data_5 PASSED
[100%]case:{'data': {'name': '', 'pwd': ''}, 'info': {'msg': '用户名和密码不能为空!', 'code': '201'}}
case[info]:{'msg': '用户名和密码不能为空!', 'code': '201'}
返回值为:{'msg': '用户名和密码不能为空!', 'code': '201'}
关闭退出浏览器

1.1.6 实例2

# -*- coding:utf-8 -*-
# 作者:NoamaNelson
# 日期:2022/11/21
# 文件名称:test_unittest_ddt1.py
# 作用:unittest数据驱动ddt
# 联系:VX(NoamaNelson)
# 博客:https://blog.csdn.net/NoamaNelsonimport unittest
from ddt import *num = [{"zhangsan": 10},{"lisi": 20},{"wangwu": 30},{"zhaoliu": 40}]
lsit_num = [10, 20, 30, 40]@ddt
class TestCase(unittest.TestCase):@data(*num)def test_case_data(self, case):m = [i for i in case.values()]print(f"case:{m[0]}")self.assertIn(m[0], lsit_num)if __name__ == '__main__':unittest.main()
Ran 4 tests in 0.000sOK
case:10
case:20
case:30
case:40

1.2 paramunittest

1.2.1 说明

  • paramunittest参数化,传入的参数类型可以是元组,列表,字典,对象,函数;
  • 通过@paramunittest.parametrized装饰器传给调用者;
  • 通过paramunittest.ParametrizedTestCase执行测试案例;
  • 通过通过setParameters方法接收装饰器传递过来的参数。

1.2.2 安装

pip install paramunittest

1.2.3 版本信息

C:\Users\Administrator>pip show paramunittest
Name: ParamUnittest
Version: 0.2
Summary: Simple extension to have parametrized unit tests.
Home-page: https://github.com/rik0/ParamUnittest
Author: Enrico Franchi
Author-email: enrico.franchi@gmail.com
License: BSD
Location: d:\python37\lib\site-packages
Requires:
Required-by:

1.2.3 实例:参数传入元组数据

# -*- coding:utf-8 -*-
# 作者:NoamaNelson
# 日期:2022/11/21
# 文件名称:test_unittest_paramunittest.py
# 作用:unittest参数化paramunittest
# 联系:VX(NoamaNelson)
# 博客:https://blog.csdn.net/NoamaNelsonimport unittest
import paramunittest# 传入元组
@paramunittest.parametrized((4, 5),(6, 7)
)
class TestCase(paramunittest.ParametrizedTestCase):def setParameters(self, n1, n2):self.n1 = n1self.n2 = n2def test_case(self):print(self.n1, self.n2)self.assertGreater(self.n2, self.n1)if __name__ == '__main__':unittest.main()
Ran 2 tests in 0.002sOK
4 5
6 7

1.2.4 实例:参数传入列表数据

# -*- coding:utf-8 -*-
# 作者:NoamaNelson
# 日期:2022/11/21
# 文件名称:test_unittest_paramunittest.py
# 作用:unittest参数化paramunittest
# 联系:VX(NoamaNelson)
# 博客:https://blog.csdn.net/NoamaNelsonimport unittest
import paramunittest# 传入列表
@paramunittest.parametrized([4, 5],[6, 7]
)
class TestCase(paramunittest.ParametrizedTestCase):def setParameters(self, n1, n2):self.n1 = n1self.n2 = n2def test_case(self):print(self.n1, self.n2)self.assertGreater(self.n2, self.n1)if __name__ == '__main__':unittest.main()
Ran 2 tests in 0.002sOK
4 5
6 7

1.2.5 实例:参数传入字典数据

# -*- coding:utf-8 -*-
# 作者:NoamaNelson
# 日期:2022/11/21
# 文件名称:test_unittest_paramunittest.py
# 作用:unittest参数化paramunittest
# 联系:VX(NoamaNelson)
# 博客:https://blog.csdn.net/NoamaNelsonimport unittest
import paramunittest# 传入字典
@paramunittest.parametrized({"n1": 4, "n2": 5},{"n1": 6, "n2": 7}
)
class TestCase(paramunittest.ParametrizedTestCase):def setParameters(self, n1, n2):self.n1 = n1self.n2 = n2def test_case(self):print(self.n1, self.n2)self.assertGreater(self.n2, self.n1)if __name__ == '__main__':unittest.main()
Ran 2 tests in 0.002sOK
4 5
6 7

1.2.6 实例:参数传入对象

# -*- coding:utf-8 -*-
# 作者:NoamaNelson
# 日期:2022/11/21
# 文件名称:test_unittest_paramunittest.py
# 作用:unittest参数化paramunittest
# 联系:VX(NoamaNelson)
# 博客:https://blog.csdn.net/NoamaNelsonimport unittest
import paramunittesttest_data = [{"n1": 4, "n2": 5}, {"n1": 6, "n2": 7}]
@paramunittest.parametrized(*test_data
)
class TestCase(paramunittest.ParametrizedTestCase):def setParameters(self, n1, n2):self.n1 = n1self.n2 = n2def test_case(self):print(self.n1, self.n2)self.assertGreater(self.n2, self.n1)if __name__ == '__main__':unittest.main()
Ran 2 tests in 0.002sOK
4 5
6 7

1.2.7 实例:参数传入函数

# -*- coding:utf-8 -*-
# 作者:NoamaNelson
# 日期:2022/11/21
# 文件名称:test_unittest_paramunittest.py
# 作用:unittest参数化paramunittest
# 联系:VX(NoamaNelson)
# 博客:https://blog.csdn.net/NoamaNelsonimport unittest
import paramunittest# 传入函数
def test_data():return [{"n1": 4, "n2": 5}, {"n1": 6, "n2": 7}]@paramunittest.parametrized(*test_data()
)
class TestCase(paramunittest.ParametrizedTestCase):def setParameters(self, n1, n2):self.n1 = n1self.n2 = n2def test_case(self):print(self.n1, self.n2)self.assertGreater(self.n2, self.n1)if __name__ == '__main__':unittest.main()
Ran 2 tests in 0.002sOK
4 5
6 7

1.2.8 实例:通过继承unittest.TestCase类执行案例

# -*- coding:utf-8 -*-
# 作者:NoamaNelson
# 日期:2022/11/21
# 文件名称:test_unittest_paramunittest.py
# 作用:unittest参数化paramunittest
# 联系:VX(NoamaNelson)
# 博客:https://blog.csdn.net/NoamaNelsonimport unittest
import paramunittest# 传入函数
def test_data():return [{"n1": 4, "n2": 5}, {"n1": 6, "n2": 7}]@paramunittest.parametrized(*test_data()
)
# class TestCase(paramunittest.ParametrizedTestCase):
#     def setParameters(self, n1, n2):
#         self.n1 = n1
#         self.n2 = n2class TestCase(unittest.TestCase):def setParameters(self, n1, n2):self.n1 = n1self.n2 = n2def test_case(self):print(self.n1, self.n2)self.assertGreater(self.n2, self.n1)if __name__ == '__main__':unittest.main()
Ran 2 tests in 0.002sOK
4 5
6 7

2 Pytest参数化

2.1 说明

pytest允许在多个级别启用测试参数化:

  • pytest.fixture() 允许fixture有参数化功能(后面学习)
  • @pytest.mark.parametrize 允许在测试函数或类中定义多组参数和fixtures
  • pytest_generate_tests 允许定义自定义参数化方案或扩展(拓展)

2.2 parametrize方法

2.2.1 参数说明

parametrize(argnames, argvalues, indirect=False, ids=None, scope=None)
参数 说明 格式 备注
argnames 参数名称 字符串"arg1,arg2,arg3" 也可以是list或者tuple
argvalues 参数值列表 [ val1,val2,val3 ] 多参数用元组存放[ (val1,val2), (val3, val4) ]
indirect 设置成True,则把传进来的参数当函数执行,而不是一个参数 / /
ids 用例的ID 字符串列表 ids的长度需要与测试数据列表的长度一致
scope 用于控制Fixture的作用范围 / 默认"function"

2.2.2使用参数化前后比对

2.2.2.1 使用前

def test_case_o():assert 10 + 10 == 20def test_case_t():assert 30 - 10 == 20def test_case_th():assert 4 * 5 == 20def test_case_f():assert 40 / 2 == 20
  • 从以上代码看,四个用例的共同规则是两个数加减乘除后进行判断;
  • 这样写需要写四个用例,感觉比较累赘;
  • 我们可以尝试使用参数化处理。

2.2.2.2 使用后

# -*- coding:utf-8 -*-
# 作者:NoamaNelson
# 日期:2022/11/21
# 文件名称:test_pytest_parametrize.py
# 作用:pytest参数化
# 联系:VX(NoamaNelson)
# 博客:https://blog.csdn.net/NoamaNelsonimport pytest@pytest.mark.parametrize("num, result", [("10 + 10", 20),("30 - 10", 20),("4 * 5", 20),("40 / 2", 20)])
def test_case(num, result):print(f"num:{num}")print(f"result:{result}")assert eval(num) == resultif __name__ == '__main__':pytest.main(["-s", "test_pytest_parametrize.py"])
test_pytest_parametrize.py
num:10 + 10
result:20
.
num:30 - 10
result:20
.
num:4 * 5
result:20
.
num:40 / 2
result:20
.

2.3 常用场景

2.3.1 装饰测试类

  • 当装饰器 @pytest.mark.parametrize 装饰测试类时,会将数据集合传递给类的所有测试用例方法。
# -*- coding:utf-8 -*-
# 作者:NoamaNelson
# 日期:2022/11/21
# 文件名称:test_pytest_parametrize1.py
# 作用:pytest参数化
# 联系:VX(NoamaNelson)
# 博客:https://blog.csdn.net/NoamaNelsonimport pytest@pytest.mark.parametrize("a, b, result", [(10, 10, 0)])
class TestP:def test_case_1(self, a, b, result):assert a - b == resultdef test_case_2(self, a, b, result):assert a - b == resultif __name__ == '__main__':pytest.main(["-s", "test_pytest_parametrize1.py"])
test_pytest_parametrize1.py ..============================== 2 passed in 0.34s ==============================

2.3.2 “笛卡尔积”,多个参数化装饰器

  • 一个函数或一个类可以装饰多个 @pytest.mark.parametrize
  • 最终生成的用例数是n*m,比如上面的代码就是:参数a的数据有3个,参数b的数据有3个,所以最终的用例数有3*3=9条。
# -*- coding:utf-8 -*-
# 作者:NoamaNelson
# 日期:2022/11/21
# 文件名称:test_pytest_parametrize2.py
# 作用:pytest参数化
# 联系:VX(NoamaNelson)
# 博客:https://blog.csdn.net/NoamaNelsonimport pytest@pytest.mark.parametrize("a", [10, 20, 30])
@pytest.mark.parametrize("b", [40, 50, 60])
def test_case_1(a, b):print(f"测试数据为{a}, {b}")if __name__ == '__main__':pytest.main(["-s", "test_pytest_parametrize2.py"])
test_pytest_parametrize2.py 测试数据为10, 40
.测试数据为20, 40
.测试数据为30, 40
.测试数据为10, 50
.测试数据为20, 50
.测试数据为30, 50
.测试数据为10, 60
.测试数据为20, 60
.测试数据为30, 60
.============================== 9 passed in 0.06s ==============================

2.3.3 参数化传入字典数据

# -*- coding:utf-8 -*-
# 作者:NoamaNelson
# 日期:2022/11/21
# 文件名称:test_pytest_parametrize3.py
# 作用:pytest参数化
# 联系:VX(NoamaNelson)
# 博客:https://blog.csdn.net/NoamaNelsonimport pytestdata = ({"xiaozhang": 23}, {"xiaoli": 25}, {"laowang": 66})@pytest.mark.parametrize("nian_ling", data)
def test_case_1(nian_ling):print(nian_ling)if __name__ == '__main__':pytest.main(["-s", "test_pytest_parametrize3.py"])
test_pytest_parametrize3.py
{'xiaozhang': 23}
.
{'xiaoli': 25}
.
{'laowang': 66}
.

2.3.4 参数化标记数据

# -*- coding:utf-8 -*-
# 作者:NoamaNelson
# 日期:2022/11/21
# 文件名称:test_pytest_parametrize4.py
# 作用:pytest参数化
# 联系:VX(NoamaNelson)
# 博客:https://blog.csdn.net/NoamaNelsonimport pytestdata = [("100+100", 200), ("400-200", 200),pytest.param("100*2", 200, marks=pytest.mark.skip),pytest.param("400/2", 100, marks=pytest.mark.xfail)]@pytest.mark.parametrize("num, result", data)
def test_case_1(num, result):print(f"num:{num}--->result:{result}")assert eval(num) == resultif __name__ == '__main__':pytest.main(["-s", "test_pytest_parametrize4.py"])
test_pytest_parametrize4.py
num:100+100--->result:200
.
num:400-200--->result:200
.
s
num:400/2--->result:100
x=================== 2 passed, 1 skipped, 1 xfailed in 0.16s ===================

2.3.5 参数化增加可读性

# -*- coding:utf-8 -*-
# 作者:NoamaNelson
# 日期:2022/11/21
# 文件名称:test_pytest_parametrize5.py
# 作用:pytest参数化
# 联系:VX(NoamaNelson)
# 博客:https://blog.csdn.net/NoamaNelsonimport pytestdata = [(10, 20, 200), (40, 50, 2000)]
ids = [f"a:{a} * b:{b} = result:{result}" for a, b, result in data]@pytest.mark.parametrize("a, b, result", data, ids=ids)
class TestCase:def test_case_1(self, a, b, result):print(f"用例1输入数据为:{a}, {b},结果为:{result}")assert a * b == resultdef test_case_2(self, a, b, result):print(f"用例2输入数据为:{a}, {b},结果为:{result}")assert a * b == resultif __name__ == '__main__':pytest.main(["-s", "test_pytest_parametrize5.py"])
test_pytest_parametrize5.py::TestCase::test_case_1[a:10 * b:20 = result:200] PASSED [ 25%]用例1输入数据为:10, 20,结果为:200test_pytest_parametrize5.py::TestCase::test_case_1[a:40 * b:50 = result:2000] PASSED [ 50%]用例1输入数据为:40, 50,结果为:2000test_pytest_parametrize5.py::TestCase::test_case_2[a:10 * b:20 = result:200] PASSED [ 75%]用例2输入数据为:10, 20,结果为:200test_pytest_parametrize5.py::TestCase::test_case_2[a:40 * b:50 = result:2000] PASSED [100%]用例2输入数据为:40, 50,结果为:2000============================== 4 passed in 0.04s ==============================
.

pytest学习和使用12-Unittest和Pytest参数化详解相关推荐

  1. Ext.Net学习笔记22:Ext.Net Tree 用法详解

    上面的图片是一个简单的树,使用Ext.Net来创建这样的树结构非常简单,代码如下: <ext:TreePanel runat="server"><Root> ...

  2. 深度学习模型训练和关键参数调优详解

    深度学习模型训练和关键参数调优详解 一.模型选择 1.回归任务 人脸关键点检测 2.分类任务 图像分类 3.场景任务 目标检测 人像分割 文字识别 二.模型训练 1.基于高层API训练模型 加载数据集 ...

  3. python列表和元组的应用_python学习笔记之列表(list)与元组(tuple)详解

    前言 最近重新再看python的基础知识,感觉自己还是对于这些知识很陌生,需要用的时候还是需要翻书查阅,还是先注重基础吧--我要重新把python的教程阅读一遍,把以前自己忽略的部分学习,加强练习和记 ...

  4. MybatisPlus学习(四)条件构造器Wrapper方法详解

    https://www.cnblogs.com/xianz666/p/13857733.html MybatisPlus学习(四)条件构造器Wrapper方法详解 文章目录 1.条件构造器 2.Que ...

  5. java 控制jsp_JSP学习之Java Web中的安全控制实例详解

    普通用户界面 修改登录的Servlet,修改后的代码如下: LoginProcess.java代码: package servlet; import javabean.User; import jav ...

  6. mount: 未知的文件系统类型“vboxsf”_好程序员云计算学习路线教程大纲课件:Mount 挂载详解...

    好程序员云计算学习路线教程大纲课件:Mount 挂载详解: ====================================================================== ...

  7. unittest之TestSuite类详解

    TestSuite 测试套件类,如何理解测试套件这个概念呢,从它的类定义来看,可以理解为:多个独立的测试用例(test case)或者多个独立的测试套件(test suite,可以理解为子套件)可以构 ...

  8. 深度学习之目标检测(十一)--DETR详解

    深度学习之目标检测(十一)-- DETR详解 目录 深度学习之目标检测(十一)-- DETR详解 1. 前言 2. DETR 框架 2.1 CNN Backbone 2.2 Transformer E ...

  9. 【强化学习】Actor-Critic(演员-评论家)算法详解

    1 Actor Critic算法简介 1.1 为什么要有Actor Critic Actor-Critic的Actor的前身是Policy Gradient,这能让它毫不费力地在连续动作中选取合适的动 ...

最新文章

  1. 安装中文版man手册,同时保留原英文版手册
  2. 里面怎么缓存图片_浏览器缓存原理总结
  3. excel 宏编程_在 Excel 中使用 Python 开发宏脚本
  4. 通过Web Services上传和下载图片文件
  5. 实现文件中名词的统计计数_Python中的统计数据展示
  6. rman命令学习-tina(上)
  7. Android手机使用Windows应用,微软宣布在你的手机应用上运行安卓APP功能向Windows 10稳定版提供...
  8. Apple越狱后超级实用的Cydia常用源推荐
  9. 2022年湖南省初级审计师考试模拟题及答案
  10. 一个小实验告诉你,内存速度到底比硬盘快多少!!!
  11. LAMP部署phpadmin
  12. 区块链是如何解决慈善公益项目中存在的问题呢?
  13. 动态规划之最大非空子段和
  14. java基于quasar实现协程池
  15. 能用网络但是个个计算机不能连上,为什么无线网络连接上却不能上网,小编教你电脑连上无线网却不能上网怎么办...
  16. 有5个人坐在一起,问第五个人多少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。问第三个人,又说比第2人大两岁。问第2个人,说比第一个人大两岁。最后问第一个人,他说是10岁。
  17. font-variant-numeric
  18. matlab三维图 魔方,matlab制作魔方图片
  19. Vue源码实现之watcher拾遗
  20. 我见过最有趣的代码注释,都在这里了

热门文章

  1. Word首页不设置页码
  2. GAE开源WEB代理mirrorrr应用
  3. 中国分省份像素地图(HTML+JS 轻量级实现地图数据展示)
  4. STM32MP157系列教程连载-Linux系统移植篇4:STM32MP1微处理器之Bootloader移植
  5. 如何用Photoshop软件制作微信文字图片?
  6. android 爬虫 协议分析,安卓逆向:分析抖音登录协议
  7. 很有价值的三堂课,以此提醒自己。
  8. Origin中使用CopyPage复制图片到Word后比例失调解决办法
  9. 【计算机考研408强化 - 操作系统】5 输入输出管理
  10. 十大H5场景制作软件大盘点