在主流测试框架中,相比于unitTest,Pytest才是永远的神

前言

如今,我们在用Python做接口自动化测试时所搭建的测试框架,大多都是Python的单元测试框架。而说起Python单元测试框架,那必然会提及unitTest和Pytest。

几乎每一个测试人,都接触过这其中一种,或者二者都有过接触。那问题来了,这两种主流框架之间到底有什么区别和特点?在未来又有怎样的发展趋势?对我们的测试生涯是否会产生影响?

关于Pytest

Pytest是Python的第三方单元测试库,长久以来一直以高效、便捷、简单的特点著称,并且扩展性极佳,可以支持应用层的复杂功能测试。

关于unitTest

unitTest是Python内嵌的标准测试库,其不仅可用于单元测试,还可用于Web自动化测试用例的开发与执行。unitTest可组织执行测试用例,并提供了丰富的断言方法用以判断测试用例是否通过。

现状

众所周知,Pytest脱胎于unitTest且对其兼容,可不必修改unitTest用例代码而执行unitTest风格用例, 此外还可扩展众多插件。相比于unitTest,Pytest支持用例出错重跑以及xdist插件。而unitTest则缺少这些功能,也几乎没有扩展,unitTest编写用例时有严格且复杂的格式,便捷性一般。

目前在行业中,大部分测试工程师都被要求熟悉Pytest 能“独立且迅速地完成基于Pytest的主流PO模式测试框架设计与实现” 已经悄然成为各大企业对测试人的基本入门需求。而仅仅熟悉unitTest的测试人,则不再像之前那样炙手可热,主流框架的发展趋势变化对我们测试人的影响已经可见一斑。

趋势

结合我的观察与经验,在这里抛出一个预想。unitTest能做的Pytest都能做,而且Pytest比unitTest更丰富高效,也更简单便捷。现在使用Pytest的人员和机构越来越多,我想大部分资深从业者都能感受出一种趋势,将来unitTest的份额极有可能会被Pytest一点点地蚕食殆尽,让我们拭目以待吧。

这里,对于还不熟悉或者不适应Pytest架构的同学,我来带大家学习下pytest.

pytest是一个非常成熟的全功能的Python测试框架,主要有以下几个特点:

  • 简单灵活,容易上手
  • 支持参数化
  • 能够支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试、接口自动化测试(pytest+requests)
  • pytest具有很多第三方插件,并且可以自定义扩展,比较好用的如pytest-selenium(集成selenium)、pytest-html(完美html测试报告生成)、pytest-rerunfailures(失败case重复执行)、pytest-xdist(多CPU分发)等
  • 测试用例的skip和xfail处理
  • 可以很好的和jenkins集成
  • report框架----allure 也支持了pytest

安装pytest:

pip install -U pytest

验证安装的版本:

pytest --version

几个pytest documentation中的例子:

例子1:

import pytest

# content of test_sample.py
def func(x):
    return x + 1
def test_answer():
    assert func(3) == 5

命令行切换到文件所在目录,执行测试(也可以直接在IDE中运行):

这个测试返回一个失败报告,因为func(3)不返回5。

例子2:
当需要编写多个测试样例的时候,我们可以将其放到一个测试类当中,如:

class TestClass:  
 def test_one(self):  
        x = "this"  
        assert 'h' in x  
  
    def test_two(self):  
        x = "hello"  
        assert hasattr(x, 'check') 

运行以上例子:

从测试结果中可以看到,该测试共执行了两个测试样例,一个失败一个成功。同样,我们也看到失败样例的详细信息,和执行过程中的中间结果。-q即-quiet,作用是减少冗长,具体就是不再展示pytest的版本信息。

如何编写pytest测试样例

通过上面2个实例,我们发现编写pytest测试样例非常简单,只需要按照下面的规则:

  • 测试文件以test_开头(以_test结尾也可以)
  • 测试类以Test开头,并且不能带有 init 方法
  • 测试函数以test_开头
  • 断言使用基本的assert即可

运行模式

Pytest的多种运行模式,让测试和调试变得更加得心应手,下面介绍5种常用的模式。在介绍之前需要提醒一句,运行pytest时会找当前目录及其子目录中的所有test_*.py 或 *_test.py格式的文件以及以test开头的方法或者class,不然就会提示找不到可以运行的case了。

1.运行后生成测试报告(htmlReport)

安装pytest-html:

pip install -U pytest-html

运行模式:

pytest --html=report.html

报告效果:

在以上报告中可以清晰的看到测试结果和错误原因,定位问题很容易。

2.运行指定的case

当我们写了较多的cases时,如果每次都要全部运行一遍,无疑是很浪费时间的,通过指定case来运行就很方便了。

例子代码:

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')

运行模式:

模式1:直接运行test_se.py文件中的所有cases:

pytest test_se.py

模式2:运行test_se.py文件中的TestClassOne这个class下的两个cases:

pytest test_se.py::TestClassOne

模式3:运行test_se.py文件中的TestClassTwo这个class下的test_one:

pytest test_se.py::TestClassTwo::test_one

注意:定义class时,需要以T开头,不然pytest是不会去运行该class的。

3.多进程运行cases

当cases量很多时,运行时间也会变的很长,如果想缩短脚本运行的时长,就可以用多进程来运行。

安装pytest-xdist:

pip install -U pytest-xdist

运行模式:

pytest test_se.py -n NUM

其中NUM填写并发的进程数。

4.重试运行cases

在做接口测试时,有事会遇到503或短时的网络波动,导致case运行失败,而这并非是我们期望的结果,此时可以就可以通过重试运行cases的方式来解决。

安装pytest-rerunfailures:

pip install -U pytest-rerunfailures

运行模式:

pytest test_se.py --reruns NUM

NUM填写重试的次数。

5.显示print内容

在运行测试脚本时,为了调试或打印一些内容,我们会在代码中加一些print内容,但是在运行pytest时,这些内容不会显示出来。如果带上-s,就可以显示了。

运行模式:

另外,pytest的多种运行模式是可以叠加执行的,比如说,你想同时运行4个进程,又想打印出print的内容。可以用:

pytest test_se.py -s -n 4

下面我还整理了一份软件测试工程师发展方向知识架构体系图。

希望大家能照着这个体系在1-2年内完成这样一个体系的构建。可以说,这个过程会让你痛不欲生,但只要你熬过去了。以后的生活就轻松很多。正所谓万事开头难,只要迈出了第一步,你就已经成功了一半,古人说的好“不积跬步,无以至千里。”等到完成之后再回顾这一段路程的时候,你肯定会感慨良多。

如果你不想再体验一次自学时找不到资料,没人解答问题,坚持几天便放弃的感受的话,可以关注我的公众号【程序员二黑】领取软件测试资源包,回复学习路线可以获取件测试工程师发展方向知识架构体系原图,还可以加入我们的群,785128166 大家一起讨论交流,里面也有各种软件测试资料和技术交流。

加油吧,测试员!如果你需要提升规划,那就行动吧,在路上总比在起点观望的要好。

未来的你肯定会感谢现在拼命的自己!

<think>好的,我现在需要比较Python中的unittestpytest这两个测试框架的区别。首先,我得回忆一下自己对这两个框架的了解,可能还需要查阅一些资料来确认细节,确保回答准确。 首先,unittestPython自带的单元测试框架,属于标准库的一部分,所以不需要额外安装。它基于JUnit的设计,采用面向对象的方式,比如测试用例需要继承TestCase类,测试方法以test开头。而pytest是第三方框架,需要单独安装,提供了更简洁的语法,可以使用函数式的方式写测试,不需要继承类。这一点应该是一个主要区别。 然后,关于断言方法。unittest提供了一系列的assert方法,比如assertEqual、assertTrue等,而pytest使用Python原生的assert语句,通过重写断言机制来提供更详细的错误信息。这可能让pytest的测试代码更简洁,错误信息更易读。 参数化测试方面,unittest需要通过subTest或者第三方库如parameterized来实现参数化,而pytest内置了@pytest.mark.parametrize装饰器,直接支持参数化,方便次测试不同输入的情况。这也是pytest的一个优势。 夹具(fixture)的处理。unittest使用setUptearDown方法在每个测试方法前后执行,而pytest的fixture系统更灵活,可以定义不同作用域的夹具,并且通过依赖注入的方式复用。这应该让pytest在管理测试资源时更高效。 测试发现机制。unittest需要测试类继承TestCase,测试方法以test开头,而pytest可以自动发现以test_开头的函数类,不需要强制继承,更灵活。此外,pytest支持更的命令行选项,比如-k选择测试用例,-m标记等,运行控制更强大。 插件系统也是pytest的一大特点,有丰富的插件生态,比如pytest-cov用于覆盖率,pytest-xdist并行测试等,而unittest的扩展性相对较弱。 另外,错误报告方面,pytest在测试失败时会提供更详细的上下文信息,比如局部变量值,帮助快速定位问题。而unittest的报告相对简单。 需要确认一下是否有其他区别,比如测试用例的组织方式、对异步测试的支持、与持续集成工具的集成等。比如pytest对异步的支持更好,可以通过pytest-asyncio插件处理async测试函数,而unittest可能需要更手动处理。 还有社区流行度,现在pytest似乎更受欢迎,因为其简洁强大的功能,而unittest由于是标准库,可能在老项目中更常见。 总结下来,主要区别点包括语法结构、断言方法、参数化、夹具系统、测试发现、插件生态、错误报告等方面。需要将这些点有条理地组织起来,对比两者的优缺点,并举例说明可能更好。 可能还需要引用相关资料,比如用户提供的引用[4]提到单元测试关注输入输出,不关注实现细节,这适用于两个框架,但pytest可能更容易实现这一点,因为代码更简洁。 最后,生成相关问题,可能需要考虑用户可能想了解如何迁移测试、如何选择框架、具体用例对比等。</think>### unittestpytest 的对比 Python主流测试框架 `unittest` `pytest` 各有特点,以下是它们的核心区别与适用场景: --- #### 1. **语法与测试结构** - **unittest** 基于类继承,需继承 `unittest.TestCase`,测试方法以 `test_` 开头,并使用 `self.assertXxx` 方法进行断言。 示例: ```python import unittest class TestMath(unittest.TestCase): def test_add(self): self.assertEqual(1 + 1, 2) ``` - **pytest** 支持函数式写法,无需继承类,直接使用 `assert` 语句。测试函数或方法以 `test_` 开头即可。 示例: ```python def test_add(): assert 1 + 1 == 2 ``` --- #### 2. **断言机制** - **unittest** 提供种断言方法(如 `assertEqual`, `assertTrue`),错误信息较基础。 ```python self.assertTrue(x in [1, 2, 3]) ``` - **pytest** 使用原生 `assert`,自动优化错误信息(如显示变量值)。 ```python assert x in [1, 2, 3] # 失败时会输出x的具体值 ``` --- #### 3. **参数化测试** - **unittest** 需借助 `subTest` 或第三方库(如 `parameterized`)实现参数化。 ```python from parameterized import parameterized class TestAdd(unittest.TestCase): @parameterized.expand([(1, 2, 3), (4, 5, 9)]) def test_add(self, a, b, expected): self.assertEqual(a + b, expected) ``` - **pytest** 内置 `@pytest.mark.parametrize` 装饰器,直接支持参数化。 ```python import pytest @pytest.mark.parametrize("a,b,expected", [(1, 2, 3), (4, 5, 9)]) def test_add(a, b, expected): assert a + b == expected ``` --- #### 4. **夹具(Fixture)管理** - **unittest** 通过 `setUp` `tearDown` 方法管理每个测试的前后逻辑,作用域限于测试类。 ```python class TestDB(unittest.TestCase): def setUp(self): self.conn = create_db_connection() def tearDown(self): self.conn.close() ``` - **pytest** 使用 `@pytest.fixture` 定义可重用的夹具,支持模块级、类级、函数级作用域,并通过依赖注入调用。 ```python import pytest @pytest.fixture def db_connection(): conn = create_db_connection() yield conn conn.close() def test_query(db_connection): result = db_connection.execute("SELECT 1") assert result == 1 ``` --- #### 5. **测试发现与执行** - **unittest** 需遵循 `TestCase` 类 `test_` 方法命名规则,执行时需通过 `python -m unittest` 命令。 - **pytest** 自动发现 `test_*.py` 文件 `test_` 开头的函数/方法,支持更灵活的命令行选项(如 `-k` 过滤用例、`-m` 标记用例)。 --- #### 6. **扩展性与插件** - **unittest** 扩展性有限,依赖标准库,复杂场景需自行封装。 - **pytest** 拥有丰富插件生态(如 `pytest-cov` 覆盖率、`pytest-xdist` 并行测试),支持定制化报告、异步测试等[^3]。 --- #### 7. **适用场景** - **unittest** 适合简单项目或需要兼容标准库的场景(如遗留代码库)[^4]。 - **pytest** 推荐用于复杂项目,尤其是需要参数化、夹具复用丰富插件支持的场景[^2]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亐㔓焼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值