测试老鸟浅谈unittest和pytest的区别
off999 2025-05-21 15:45 40 浏览 0 评论
一、unittest
# MyFunction.py
def add(a, b):
return a + b
1.unittest单元测试
# 单元测试.py
"""
1、单元测试框架:自动校验结果
python:unittest或者pytest、Java:Junit、TestNG
怎么写用例:
必须以test开头
查找用例
参数化
"""
import unittest
import myFunction
import HTMLTestRunner
import HTMLTestRunnerNew # 测试报告丰富版本
import parameterized # 参数化
class TestAdd(unittest.TestCase):
'''测试add方法'''
def testAddNormal1(self):
"""正常的测试加法,by huozi"""
result = myFunction.add(1, 2)
self.assertEqual(3, result, )
def testAddNormal2(self):
"""正常的测试加法,带有msg返回信息"""
result = myFunction.add(4, 2)
self.assertEqual(6, result, '正常case通过')
def testAddError1(self):
"""测试失败使用,by huozi"""
result = myFunction.add(0, 2)
self.assertEqual(4, result)
def testAddError2(self):
"""测试失败使用带有msg返回信息的"""
result = myFunction.add(1, 2)
self.assertEqual(0, result, '正常整数加法,没有通过')
@parameterized.parameterized.expand( # 传参为二维数组
[[1, 2, 3, '参数化1'],
[-1, 2, 3, '参数化2'],
[2, 4, 7, '参数化3']]
)
def testParamAdd(self, a, b, c, desc):
self._testMethodDoc = desc # 使用这个_testMethodDoc参数传递
result = myFunction.add(a, b)
self.assertEqual(c, result, '预期结果是%s,实际结果是%s' % (c, result))
if __name__ == '__main__':
# 写法0:不产生测试报告
# unittest.main() # 执行所有用例
# 写法1:运行单个测试用例
testSuite1 = unittest.TestSuite()
testSuite1.addTest(TestAdd('testAddNormal')) # 运行单个测试用例
# testSuite.addTest(TestAdd('testAddError1'))
# testSuite.addTest(TestAdd('testAddError1'))
# 写法2:运行某个类里面的测试用例
testSuite2 = unittest.makeSuite(TestAdd) # 运行某个类(如TestAdd)里面所有的测试用例
# 写法3:查找某个目录下的测试用例(绝对路径),文件必须以test开头,所有文件就是:*.py
testSuite3 = unittest.defaultTestLoader.discover('/Users/ray/PycharmProjects/tmz/day9/cases', 'test*.py')
with open('report.html', 'wb') as fw:
# runner = HTMLTestRunner.HTMLTestRunner(stream=fw, title='天马测试报告', description='天马测试',verbosity=3)
runner = HTMLTestRunnerNew.HTMLTestRunner(stream=fw, title='天马测试报告', description='天马测试', verbosity=3)
runner.run(testSuite2)
二、pytest
1.pytest单元测试
class TestClassOne(object):
def test_one(self):
x = "this"
assert 't'in x
def test_two(self):
x = "hello"
assert hasattr(x, 'check')
class TestClassTwo(object):
def test_one(self):
x = "iphone"
assert 'p'in x
def test_two(self):
x = "apple"
assert hasattr(x, 'check')
三、unittest和pytest的区别
1 用例编写规则
unittest提供了test cases、test suites、test fixtures、test runner相关的类,让测试更加明确、方便、可控。使用unittest编写用例,必须遵守以下规则:- 测试文件必须先import unittest
- 测试类必须继承unittest.TestCase
- 测试方法必须以“test_”开头
- 测试类必须要有unittest.main()方法
pytest是python的第三方测试框架,是基于unittest的扩展框架,比unittest更简洁,更高效。使用pytest编写用例,必须遵守以下规则:- 测试文件名必须以“test_”开头或者"_test"结尾(如:test_ab.py)
- 测试方法必须以“test_”开头。
- 测试类命名以"Test"开头。
总结: pytest可以执行unittest风格的测试用例,无须修改unittest用例的任何代码,有较好的兼容性。 pytest插件丰富,比如flask插件,可用于用例出错重跑;还有xdist插件,可用于设备并行执行。
2 用例前置和后置
- 1 用例编写规则提供了setUp/tearDown,每个用例运行前、结束后运行一次。setUpClass和tearDownClass,用例执行前、结束后,只运行一次。
# unittset前置条件.py
import unittest
class Test(unittest.TestCase): # 继承unittest中的TestCase
@classmethod
def setUpClass(cls) -> None: # setUpClass:所有用例执行之前会执行一次,如:打开文件,链接数据库
print('setUpClass')
@classmethod
def tearDownClass(cls) -> None: # tearDownClass:所有用例执行之后会执行一次,如:注册后删掉数据
print('tearDownClass')
@classmethod
def setUp(self) -> None: # setUp:每条用例执行前都会先执行setUp,如:
print('setUp')
@classmethod
def tearDown(self) -> None: # tearDown:每条用例执行后都会先执行tearDown,如:
print('tearDown')
def testB(self): # 用例执行顺序:以test后字母开头排序
print('testB')
def testA(self):
print('testA')
def testZ(self):
print('testZ')
if __name__ == "__main__":
# unittest.main() # 不产生测试报告
pass
其执行结果如下:
Ran 3 tests in 0.003s
Launching unittests with arguments python -m unittest 用例前置条件.Test in /Users/ray/PycharmProjects/day10
OK
setUpClass
tearDownClass
Process finished with exit code 0
setUp
testA
tearDown
setUp
testB
tearDown
setUp
testZ
tearDown
pytest提供了模块级、函数级、类级、方法级的setup/teardown,比unittest的setUp/tearDown更灵活。
import pytest
# 模块中的方法
def setup_module():
print("setup_module:整个.py模块只执行一次")
def teardown_module():
print("teardown_module:整个test_module.py模块只执行一次")
def setup_function():
print("setup_function:每个用例开始前都会执行")
def teardown_function():
print("teardown_function:每个用例结束后都会执行")
# 测试模块中的用例1
def test_one():
print("正在执行测试模块----test_one")
x = "this"
assert 'h' in x
# 测试模块中的用例2
def test_two():
print("正在执行测试模块----test_two")
x = "hello"
assert hasattr(x, 'check')
# 测试类
class TestCase():
def setup_class(self):
print("setup_class:所有用例执行之前")
def teardown_class(self):
print("teardown_class:所有用例执行之后")
def setup(self):
print("setup:每个用例开始前都会执行")
def teardown(self):
print("teardown:每个用例结束后都会执行")
def test_three(self):
print("正在执行测试类----test_three")
x = "this"
assert 'h' in x
def test_four(self):
print("正在执行测试类----test_four")
x = "hello"
assert hasattr(x, 'check')
if __name__ == "__main__":
pytest.main(["-s", "test_module.py"])
其执行结果如下:
collected 4 items
test_module.py setup_module:整个.py模块只执行一次
setup_function:每个用例开始前都会执行
正在执行测试模块----test_one
.teardown_function:每个用例结束后都会执行
setup_function:每个用例开始前都会执行
正在执行测试模块----test_two
Fteardown_function:每个用例结束后都会执行
setup_class:所有用例执行之前
setup:每个用例开始前都会执行
正在执行测试类----test_three
.teardown:每个用例结束后都会执行
setup:每个用例开始前都会执行
正在执行测试类----test_four
Fteardown:每个用例结束后都会执行
teardown_class:所有用例执行之后
teardown_module:整个test_module.py模块只执行一次
方法二:pytest的fixture方法
# conftest.py
# -*- coding: utf-8 -*-
import pytest
@pytest.fixture(scope="function")
def login():
print("请先输入账号和密码,然后登陆")
yield
print("退出登陆")
# test_1.py
# -*- coding: utf-8 -*-
import pytest
def test_fix1(login):
print("test_fix1 in test_1.py:需要登陆再执行操作")
def test_fix2():
print("test_fix2 in test_1.py:不需要登陆再执行操作")
def test_fix3(login):
print("test_fix3 in test_1.py:需要登陆再执行操作")
if __name__ == "__main__":
pytest.main(['-s', 'test_1.py'])
# test_2.py
# -*- coding: utf-8 -*-
import pytest
def test_fix3():
print("test_fix3 in test_2.py:不需要登陆再执行操作")
def test_fix4(login):
print("test_fix4 in test_2.py:需要登陆再执行操作")
if __name__ == "__main__":
pytest.main(['-s', 'test_2.py'])
其执行结果如下:
pytest -s test_1.py
collected 3 items
test_1.py 请先输入账号和密码,然后登陆
test_fix1 in test_1.py:需要登陆再执行操作
.退出登陆
test_fix2 in test_1.py:不需要登陆再执行操作
.请先输入账号和密码,然后登陆
test_fix3 in test_1.py:需要登陆再执行操作
.退出登陆
3 断言
- unittest提供了assertEqual、assertIn、assertTrue、assertFalse。
assertEqual:判断断言第一个参数和第二个参数是否相等,如果不相等则测试失败
用法: assertIn(key, container, message)
- key:在给定容器中检查其存在性的字符串
- container:在其中搜索关键字符串的字符串
- message:作为测试消息失败时显示的消息的字符串语句。
assertIn:用于单元测试中以检查字符串是否包含在其他字符串中。此函数将使用三个字符串参数作为输入,并根据断言条件返回一个布尔值。如果 key 包含在容器字符串中,它将返回true,否则返回false。
用法: assertIn(key, container, message)
参数:assertIn()接受以下三个参数的说明:
- key:在给定容器中检查其存在性的字符串
- container:在其中搜索关键字符串的字符串
- message:作为测试消息失败时显示的消息的字符串语句。
assertTrue:判断是否为真
assertFalse:判断是否为假
- pytest直接使用assert表达式。
assert:用于判断一个表达式,在表达式条件为 false 的时候触发异常。
4 报告
- unittest使用HTMLTestRunnerNew库。
- pytest有pytest-HTML、allure插件。
5 失败重跑
- unittest无此功能。
- pytest支持用例执行失败重跑,pytest-rerunfailures插件。
6 参数化
- unittest需依赖ddt库或者parameterized库。
# 单元测试.py
import unittest
import myFunction
import HTMLTestRunner
import HTMLTestRunnerNew # 测试报告丰富版本
import parameterized # 参数化
class TestAdd(unittest.TestCase):
'''测试add方法'''
@parameterized.parameterized.expand( # 传参为二维数组
[[1, 2, 3, '参数化1'],
[-1, 2, 3, '参数化2'],
[2, 4, 7, '参数化3']]
)
def testParamAdd(self, a, b, c, desc):
self._testMethodDoc = desc # 使用这个_testMethodDoc参数传递
result = myFunction.add(a, b)
self.assertEqual(c, result, '预期结果是%s,实际结果是%s' % (c, result))
pytest直接使用@pytest.mark.parametrize装饰器。
@allure.epic("SOS接口自动化测试")
class TestCaseRunner:
@allure.feature("过程管理/风险处理/干预任务报表(新)-查询")
@pytest.mark.parametrize("case", CaseExcuteUtils.get_case_list("soscases/progressManagement/taskreport", case_tag))
def test_task_report(self, case):
"""
参数化执行测试用例
:param case:
:return:
"""
print(case.description)
allure.dynamic.title(case.description)
CaseExcuteUtils.excute_case(case, data)
7 用例分类执行
- unittest默认执行全部测试用例,可以通过加载testsuite执行部分模块测试用例;
- pytest可以通过@pytest.mark来标记测试用例,执行命令加上参数“-m”即可运行标记的用例。
相关推荐
- win8专业版和家庭版的区别(win8专业版和家庭版的区别在哪)
-
win10有七种版本:家庭版、企业版、教育版、移动版、移动企业版以及针对物联网设备及嵌入式系统设计的版本。据个人理解家庭版与家庭中文版是一个意思,是家庭版的不同语言版本,你升级的时候,会自动升级到对应...
- 手机开不了机怎么办一直黑屏
-
原因可能有很多:系统崩溃。刷机失败,手机电池用尽。可以通过以下方法检测:1.首先,对手机进行自我检测。现在大多数品牌手机都有深度休眠模式,一旦进入这种模式,经常会造成手机黑屏,无法开机。解决的...
- 主题商店官方下载(vivi主题商店下载)
-
1首先上小米官网注册设计师账号您可以登录主题设计师站上传。designer.xiaomi.com/2下载小米主题制作器3打包成mtz格式4上传等待审核(如果只是自己用的话就不用上传)在软件商店里搜...
- 360邮箱登录(360邮箱登录入口在哪里)
-
可以修改登录邮箱的,不自己亲自尝试一下,还真是觉的好麻烦,尤其是在你要修改的邮箱已经被注册的时候,如果你知道了,就很简单,不知道的,希望你再修改的时候不要多走弯路,下面我给大家详细讲解。1首先,我们要...
- win10自动更新后桌面文件全没了
-
打开控制面板,找到用户账户,看看有几个账户。如果有多个账户,则重新启动计算机,登录另一个账户,看看桌面文件是否回来了。以上方法未成功,则在整个电脑里搜索以前的那个文件夹。搜索也找不到,就下载并安装一个...
- 三星固态硬盘(三星固态硬盘序列号查询官网)
-
您可以通过访问三星官方网站的支持页面来查询三星固态硬盘的序列号。在支持页面中,您可以找到一个名为"产品注册"或"产品查询"的选项。点击该选项后,您将被要求输入您的固态硬...
- 手机恢复出厂设置后数据能恢复吗
-
1、首先来说如果点击了“恢复出厂设置”朋友们完全不用惊慌,因为手机上的数据还是能够找回来的。2、在网上找一款免费的手机恢复数据软件,例如安卓上的应用手机数据恢复精灵,根据手机恢复数据软件向导式提醒进行...
- 万能浏览器手机版下载安装(万能浏览器手机版下载安装最新版)
-
用起来还是挺靠谱的,但是可能会有捆绑的恶意软件,各种弹窗很烦人OPPO手机浏览器搜索网站的方法:在页面顶部的搜索栏输入URL或搜索关键字。搜索栏下会出现搜索建议,可直接点击符合你搜索目标的建议。点击搜...
- windows彻底关闭自动更新(关闭windows 自动更新)
-
方法一:Windows设置 要想关闭Win10自动更新,比较简单的一种方法就是进入到Windows设置中,将Windows更新直接关闭。步骤如下: 1、按“Windows+I”键,打开Wind...
- potplayer安卓版官网(potplayer apk下载)
-
教程如下:Potplayer是一款非常强大的媒体播放器,是由原KMPlayer的制作者自己开发的,软件体积小,功能强大,占用内存非常小,其软件内置解码器几乎能播放任何格式的媒体文件,而且软件本身没有任...
-
- 十大公认最耐用的台式电脑(哪个品牌的台式机电脑最耐用)
-
一般来说,品牌机没有单卖的,都是成套的主机显示器一起销售的,如果价格不是问题,单说耐用,个人感觉还是IBM的耐用,再其次什么戴尔,联想,华硕,宏碁什么的也都可以。惠普台式电脑和戴尔台式电脑相比较,肯定是戴尔台式电脑的质量比较好,因为戴尔台...
-
2025-12-13 13:03 off999
- 360下载的软件不在桌面上(电脑下载360为什么不在桌面)
-
方法如下。打开360浏览器的设置按钮,在设置中选择将下载的文件浏览到桌面,点击应用保存,这是即可将360文件下载的内容直接储存到桌面上。可以选择F3进行搜索,搜到360浏览器之后打开他的这个文件夹,找...
- 电脑读不了u盘怎么回事(电脑读不出u盘了)
-
方法1:取消勾选“隐藏的驱动器” 1、首先要排除是不是U盘损坏的问题,当U盘插入到其他电脑,如果可以读出来,那么肯定不是U盘的问题了。 2、很有可能是U盘在你的电脑上被隐藏了,将U盘插入电脑后,打...
- ps2游戏iso镜像下载(ps2游戏镜像格式)
-
什么格式都有,网上下的有CDI或者NRG,我自己转的MDF也可以玩,当然转成ISO也可以玩.不用看到光盘的实际文件后再制作镜像文件,你只要通过专门的镜像制作软件将整个光盘完整的克隆出来就行了,制作PS...
- 虚拟机安装教程win7镜像文件下载
-
要下载虚拟机的镜像系统,首先你需要确定你想要安装的虚拟机系统类型(比如VMware、VirtualBox、Hyper-V等),然后前往官方网站或认可的第三方网站,找到所需的镜像系统下载链接。在下载镜像...
欢迎 你 发表评论:
- 一周热门
-
-
抖音上好看的小姐姐,Python给你都下载了
-
全网最简单易懂!495页Python漫画教程,高清PDF版免费下载
-
Python 3.14 的 UUIDv6/v7/v8 上新,别再用 uuid4 () 啦!
-
飞牛NAS部署TVGate Docker项目,实现内网一键转发、代理、jx
-
python入门到脱坑 输入与输出—str()函数
-
宝塔面板如何添加免费waf防火墙?(宝塔面板开启https)
-
Python三目运算基础与进阶_python三目运算符判断三个变量
-
(新版)Python 分布式爬虫与 JS 逆向进阶实战吾爱分享
-
失业程序员复习python笔记——条件与循环
-
使用 python-fire 快速构建 CLI_如何搭建python项目架构
-
- 最近发表
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python进度条 (67)
- python吧 (67)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python列表切片 (59)
- python面向对象编程 (60)
- python 代码加密 (65)
- python串口编程 (77)
- python封装 (57)
- python写入txt (66)
- python读取文件夹下所有文件 (59)
- python操作mysql数据库 (66)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)
