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


    目录

    一、unittest

    1 unittest单元测试

    二、pytest

    1 pytest单元测试

    三、unittest和pytest的区别

    3 用例编写规则

    2 用例前置和后置

    3 断言

    4 报告

    5 失败重跑

    6 参数化

    7 用例分类执行


    一、unittest

    1. # MyFunction.py
    2. def add(a, b):
    3. return a + b

    1 unittest单元测试

    1. # 单元测试.py
    2. """
    3. 1、单元测试框架:自动校验结果
    4. python:unittest或者pytest、Java:Junit、TestNG
    5. 怎么写用例:
    6. 必须以test开头
    7. 查找用例
    8. 参数化
    9. """
    10. import unittest
    11. import myFunction
    12. import HTMLTestRunner
    13. import HTMLTestRunnerNew # 测试报告丰富版本
    14. import parameterized # 参数化
    15. class TestAdd(unittest.TestCase):
    16. '''测试add方法'''
    17. def testAddNormal1(self):
    18. """正常的测试加法,by huozi"""
    19. result = myFunction.add(1, 2)
    20. self.assertEqual(3, result, )
    21. def testAddNormal2(self):
    22. """正常的测试加法,带有msg返回信息"""
    23. result = myFunction.add(4, 2)
    24. self.assertEqual(6, result, '正常case通过')
    25. def testAddError1(self):
    26. """测试失败使用,by huozi"""
    27. result = myFunction.add(0, 2)
    28. self.assertEqual(4, result)
    29. def testAddError2(self):
    30. """测试失败使用带有msg返回信息的"""
    31. result = myFunction.add(1, 2)
    32. self.assertEqual(0, result, '正常整数加法,没有通过')
    33. @parameterized.parameterized.expand( # 传参为二维数组
    34. [[1, 2, 3, '参数化1'],
    35. [-1, 2, 3, '参数化2'],
    36. [2, 4, 7, '参数化3']]
    37. )
    38. def testParamAdd(self, a, b, c, desc):
    39. self._testMethodDoc = desc # 使用这个_testMethodDoc参数传递
    40. result = myFunction.add(a, b)
    41. self.assertEqual(c, result, '预期结果是%s,实际结果是%s' % (c, result))
    42. if __name__ == '__main__':
    43. # 写法0:不产生测试报告
    44. # unittest.main() # 执行所有用例
    45. # 写法1:运行单个测试用例
    46. testSuite1 = unittest.TestSuite()
    47. testSuite1.addTest(TestAdd('testAddNormal')) # 运行单个测试用例
    48. # testSuite.addTest(TestAdd('testAddError1'))
    49. # testSuite.addTest(TestAdd('testAddError1'))
    50. # 写法2:运行某个类里面的测试用例
    51. testSuite2 = unittest.makeSuite(TestAdd) # 运行某个类(如TestAdd)里面所有的测试用例
    52. # 写法3:查找某个目录下的测试用例(绝对路径),文件必须以test开头,所有文件就是:*.py
    53. testSuite3 = unittest.defaultTestLoader.discover('/Users/ray/PycharmProjects/tmz/day9/cases', 'test*.py')
    54. with open('report.html', 'wb') as fw:
    55. # runner = HTMLTestRunner.HTMLTestRunner(stream=fw, title='天马测试报告', description='天马测试',verbosity=3)
    56. runner = HTMLTestRunnerNew.HTMLTestRunner(stream=fw, title='天马测试报告', description='天马测试', verbosity=3)
    57. runner.run(testSuite2)

    二、pytest

    1 pytest单元测试

    1. class TestClassOne(object):
    2. def test_one(self):
    3. x = "this"
    4. assert 't'in x
    5. def test_two(self):
    6. x = "hello"
    7. assert hasattr(x, 'check')
    8. class TestClassTwo(object):
    9. def test_one(self):
    10. x = "iphone"
    11. assert 'p'in x
    12. def test_two(self):
    13. x = "apple"
    14. assert hasattr(x, 'check')

    三、unittest和pytest的区别

    1用例编写规则

    unittest提供了test cases、test suites、test fixtures、test runner相关的类,让测试更加明确、方便、可控。使用unittest编写用例,必须遵守以下规则:

    1. 测试文件必须先import unittest
    2. 测试类必须继承unittest.TestCase
    3. 测试方法必须以“test_”开头
    4. 测试类必须要有unittest.main()方法

    pytest是python的第三方测试框架,是基于unittest的扩展框架,比unittest更简洁,更高效。使用pytest编写用例,必须遵守以下规则:

    1. 测试文件名必须以“test_”开头或者"_test"结尾(如:test_ab.py)
    2. 测试方法必须以“test_”开头。
    3. 测试类命名以"Test"开头。

      总结: pytest可以执行unittest风格的测试用例,无须修改unittest用例的任何代码,有较好的兼容性。 pytest插件丰富,比如flask插件,可用于用例出错重跑;还有xdist插件,可用于设备并行执行。     

    2 用例前置和后置

    1. unittest提供了setUp/tearDown,每个用例运行前、结束后运行一次。setUpClass和tearDownClass,用例执行前、结束后,只运行一次。
    1. # unittset前置条件.py
    2. import unittest
    3. class Test(unittest.TestCase): # 继承unittest中的TestCase
    4. @classmethod
    5. def setUpClass(cls) -> None: # setUpClass:所有用例执行之前会执行一次,如:打开文件,链接数据库
    6. print('setUpClass')
    7. @classmethod
    8. def tearDownClass(cls) -> None: # tearDownClass:所有用例执行之后会执行一次,如:注册后删掉数据
    9. print('tearDownClass')
    10. @classmethod
    11. def setUp(self) -> None: # setUp:每条用例执行前都会先执行setUp,如:
    12. print('setUp')
    13. @classmethod
    14. def tearDown(self) -> None: # tearDown:每条用例执行后都会先执行tearDown,如:
    15. print('tearDown')
    16. def testB(self): # 用例执行顺序:以test后字母开头排序
    17. print('testB')
    18. def testA(self):
    19. print('testA')
    20. def testZ(self):
    21. print('testZ')
    22. if __name__ == "__main__":
    23. # unittest.main() # 不产生测试报告
    24. pass

    其执行结果如下:

    1. Ran 3 tests in 0.003s
    2. Launching unittests with arguments python -m unittest 用例前置条件.Test in /Users/ray/PycharmProjects/day10
    3. OK
    4. setUpClass
    5. tearDownClass
    6. Process finished with exit code 0
    7. setUp
    8. testA
    9. tearDown
    10. setUp
    11. testB
    12. tearDown
    13. setUp
    14. testZ
    15. tearDown
    1. pytest提供了模块级、函数级、类级、方法级的setup/teardown,比unittest的setUp/tearDown更灵活。
    1. import pytest
    2. # 模块中的方法
    3. def setup_module():
    4. print("setup_module:整个.py模块只执行一次")
    5. def teardown_module():
    6. print("teardown_module:整个test_module.py模块只执行一次")
    7. def setup_function():
    8. print("setup_function:每个用例开始前都会执行")
    9. def teardown_function():
    10. print("teardown_function:每个用例结束后都会执行")
    11. # 测试模块中的用例1
    12. def test_one():
    13. print("正在执行测试模块----test_one")
    14. x = "this"
    15. assert 'h' in x
    16. # 测试模块中的用例2
    17. def test_two():
    18. print("正在执行测试模块----test_two")
    19. x = "hello"
    20. assert hasattr(x, 'check')
    21. # 测试类
    22. class TestCase():
    23. def setup_class(self):
    24. print("setup_class:所有用例执行之前")
    25. def teardown_class(self):
    26. print("teardown_class:所有用例执行之后")
    27. def setup(self):
    28. print("setup:每个用例开始前都会执行")
    29. def teardown(self):
    30. print("teardown:每个用例结束后都会执行")
    31. def test_three(self):
    32. print("正在执行测试类----test_three")
    33. x = "this"
    34. assert 'h' in x
    35. def test_four(self):
    36. print("正在执行测试类----test_four")
    37. x = "hello"
    38. assert hasattr(x, 'check')
    39. if __name__ == "__main__":
    40. pytest.main(["-s", "test_module.py"])

    其执行结果如下:

    1. collected 4 items
    2. test_module.py setup_module:整个.py模块只执行一次
    3. setup_function:每个用例开始前都会执行
    4. 正在执行测试模块----test_one
    5. .teardown_function:每个用例结束后都会执行
    6. setup_function:每个用例开始前都会执行
    7. 正在执行测试模块----test_two
    8. Fteardown_function:每个用例结束后都会执行
    9. setup_class:所有用例执行之前
    10. setup:每个用例开始前都会执行
    11. 正在执行测试类----test_three
    12. .teardown:每个用例结束后都会执行
    13. setup:每个用例开始前都会执行
    14. 正在执行测试类----test_four
    15. Fteardown:每个用例结束后都会执行
    16. teardown_class:所有用例执行之后
    17. teardown_module:整个test_module.py模块只执行一次

    方法二:pytest的fixture方法

    1. # conftest.py
    2. # -*- coding: utf-8 -*-
    3. import pytest
    4. @pytest.fixture(scope="function")
    5. def login():
    6. print("请先输入账号和密码,然后登陆")
    7. yield
    8. print("退出登陆")
    1. # test_1.py
    2. # -*- coding: utf-8 -*-
    3. import pytest
    4. def test_fix1(login):
    5. print("test_fix1 in test_1.py:需要登陆再执行操作")
    6. def test_fix2():
    7. print("test_fix2 in test_1.py:不需要登陆再执行操作")
    8. def test_fix3(login):
    9. print("test_fix3 in test_1.py:需要登陆再执行操作")
    10. if __name__ == "__main__":
    11. pytest.main(['-s', 'test_1.py'])
    1. # test_2.py
    2. # -*- coding: utf-8 -*-
    3. import pytest
    4. def test_fix3():
    5. print("test_fix3 in test_2.py:不需要登陆再执行操作")
    6. def test_fix4(login):
    7. print("test_fix4 in test_2.py:需要登陆再执行操作")
    8. if __name__ == "__main__":
    9. pytest.main(['-s', 'test_2.py'])

    其执行结果如下:

    1. pytest -s test_1.py
    2. collected 3 items
    3. test_1.py 请先输入账号和密码,然后登陆
    4. test_fix1 in test_1.py:需要登陆再执行操作
    5. .退出登陆
    6. test_fix2 in test_1.py:不需要登陆再执行操作
    7. .请先输入账号和密码,然后登陆
    8. test_fix3 in test_1.py:需要登陆再执行操作
    9. .退出登陆

    3 断言

    1. 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:判断是否为假

    1. pytest直接使用assert表达式。

    assert:用于判断一个表达式,在表达式条件为 false 的时候触发异常。

    4 报告

    1. unittest使用HTMLTestRunnerNew库。
    2. pytest有pytest-HTML、allure插件。

    5 失败重跑

    1. unittest无此功能。
    2. pytest支持用例执行失败重跑,pytest-rerunfailures插件。

    6 参数化

    1. unittest需依赖ddt库或者parameterized库。
    1. # 单元测试.py
    2. import unittest
    3. import myFunction
    4. import HTMLTestRunner
    5. import HTMLTestRunnerNew # 测试报告丰富版本
    6. import parameterized # 参数化
    7. class TestAdd(unittest.TestCase):
    8. '''测试add方法'''
    9. @parameterized.parameterized.expand( # 传参为二维数组
    10. [[1, 2, 3, '参数化1'],
    11. [-1, 2, 3, '参数化2'],
    12. [2, 4, 7, '参数化3']]
    13. )
    14. def testParamAdd(self, a, b, c, desc):
    15. self._testMethodDoc = desc # 使用这个_testMethodDoc参数传递
    16. result = myFunction.add(a, b)
    17. self.assertEqual(c, result, '预期结果是%s,实际结果是%s' % (c, result))
    1. pytest直接使用@pytest.mark.parametrize装饰器。
    1. @allure.epic("SOS接口自动化测试")
    2. class TestCaseRunner:
    3. @allure.feature("过程管理/风险处理/干预任务报表(新)-查询")
    4. @pytest.mark.parametrize("case", CaseExcuteUtils.get_case_list("soscases/progressManagement/taskreport", case_tag))
    5. def test_task_report(self, case):
    6. """
    7. 参数化执行测试用例
    8. :param case:
    9. :return:
    10. """
    11. print(case.description)
    12. allure.dynamic.title(case.description)
    13. CaseExcuteUtils.excute_case(case, data)

    7 用例分类执行

    1. unittest默认执行全部测试用例,可以通过加载testsuite执行部分模块测试用例;
    2. pytest可以通过@pytest.mark来标记测试用例,执行命令加上参数“-m”即可运行标记的用例。


     

  • 相关阅读:
    使用Visual Studio 2022 创建lib和dll并使用
    ENSP中用OSPF协议在MGRE结构中实现全网可达
    PHP代码审计工具
    探讨:UDP广播还有前途吗?(代码验证)
    java毕业设计房产中介管理系统Mybatis+系统+数据库+调试部署
    【OAuth2】二十、OAuth2扩展协议 PKCE
    VB.NET—窗体引起的乌龙事件
    2021年度聚合支付评级如何?
    大模型时代的具身智能系列专题(九)
    Kotlin挂起函数整理-基础
  • 原文地址:https://blog.csdn.net/m0_68405758/article/details/125473733