为了账号安全,请及时绑定邮箱和手机立即绑定

测试老鸟浅谈unittest和pytest的区别

标签:
MySQL

# MyFunction.pydef add(a, b): return a + b

1.unittest单元测试

# 单元测试.py""“1、单元测试框架:自动校验结果 python:unittest或者pytest、Java:Junit、TestNG 怎么写用例: 必须以test开头 查找用例 参数化”"“import unittestimport myFunctionimport HTMLTestRunnerimport 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)

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提供了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插件,可用于设备并行执行。

1 用例编写规则提供了setUp/tearDown,每个用例运行前、结束后运行一次。setUpClass和tearDownClass,用例执行前、结束后,只运行一次。

# unittset前置条件.pyimport unittestclass 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.003sLaunching unittests with arguments python -m unittest 用例前置条件.Test in /Users/ray/PycharmProjects/day10OKsetUpClasstearDownClassProcess finished with exit code 0setUptestAtearDownsetUptestBtearDownsetUptestZtearDown

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:每个用例结束后都会执行”)# 测试模块中的用例1def test_one(): print(“正在执行测试模块----test_one”) x=“this” assert ‘h’ in x# 测试模块中的用例2def 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_twoFteardown_function:每个用例结束后都会执行setup_class:所有用例执行之前setup:每个用例开始前都会执行正在执行测试类----test_three.teardown:每个用例结束后都会执行setup:每个用例开始前都会执行正在执行测试类----test_fourFteardown:每个用例结束后都会执行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 pytestdef 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 pytestdef 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.pycollected 3 items test_1.py 请先输入账号和密码,然后登陆test_fix1 in test_1.py:需要登陆再执行操作.退出登陆test_fix2 in test_1.py:不需要登陆再执行操作.请先输入账号和密码,然后登陆test_fix3 in test_1.py:需要登陆再执行操作.退出登陆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 的时候触发异常。

unittest使用HTMLTestRunnerNew库。pytest有pytest-HTML、allure插件。unittest无此功能。pytest支持用例执行失败重跑,pytest-rerunfailures插件。unittest需依赖ddt库或者parameterized库。

# 单元测试.pyimport unittestimport myFunctionimport HTMLTestRunnerimport 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)unittest默认执行全部测试用例,可以通过加载testsuite执行部分模块测试用例;pytest可以通过@pytest.mark来标记测试用例,执行命令加上参数“-m”即可运行标记的用例。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消