测试框架怎么选?unittest 与 pytest 的正面交锋

框架选不对,后面写脚本会很难受。这不是夸张——我个人最早接触集成测试时,一上来就用了 unittest,结果越写越憋屈。后来换了 pytest,感觉像是换了一把顺手的刀。今天咱们就仔细聊聊这两个框架,看看它们各自的特点,以及实际项目中怎么选。

unittest:Python 自带的“老将”

unittest 是 Python 标准库的一部分,说白了就是官方自带的测试框架。它在设计上借鉴了 Java 的 JUnit,所以如果你写过 Java,上手会很快。

但说实话,unittest 的语法有些啰嗦。你要写测试类,要继承 unittest.TestCase,还要主动调用 assertEqual、assertTrue 那一套。我刚开始做测试时,光记这些断言方法就花了些时间。

unittest 的典型写法

import unittest

class TestCalculator(unittest.TestCase):
    def test_add(self):
        result = 2 + 3
        self.assertEqual(result, 5)

    def test_subtract(self):
        result = 5 - 3
        self.assertEqual(result, 2)

if __name__ == '__main__':
    unittest.main()

嗯,这里要注意:unittest 要求测试方法必须以 test_ 开头,否则框架不会识别它。而且,setup 和 teardown 你得写成 setUp 和 tearDown,大小写写错了不会报错,只会默默不执行。我在项目中遇到过有人因为拼写错误,导致数据清理逻辑没跑,数据库里留下一堆脏数据。

pytest:简洁、强大、社区活跃

pytest 是第三方框架,但它的简洁程度让人眼前一亮。你不需要写类,不需要继承,直接用普通函数写断言就能跑。为什么?因为 pytest 自动发现了测试文件并执行。

我个人习惯用 pytest 写集成测试,因为它的 fixture(夹具)机制特别灵活。你可以把一个数据库连接、一个 API 客户端,甚至整个环境上下文都注入到测试函数里。

pytest 的典型写法

def test_add():
    result = 2 + 3
    assert result == 5

def test_subtract():
    result = 5 - 3
    assert result == 2

看到区别了吗?pytest 直接用 assert 关键字,不需要记那些断言方法。而且测试方法不需要放在类里,普通函数就行。你想想看,这少写了多少模板代码?

核心差异对比

为了让你看得更清楚,我整理了一张对比表。这些差异不只在语法层面,还会影响你的测试维护成本。

对比维度 unittest pytest
测试发现 必须继承 TestCase 自动发现所有 test_ 开头的函数
断言方式 self.assertEqual() 等 assert 关键字,更直观
夹具机制 setUp/tearDown 重写 @pytest.fixture 装饰器
参数化测试 需要写子测试或循环 @pytest.mark.parametrize
插件生态 较少 非常丰富(pytest-xdist、pytest-cov 等)
执行速度 一般 更快(支持并行)
错误信息 基础信息 详细的上下文和上下文对比

避坑提示:如果你有大量已有的 unittest 测试,别急着全部重写成 pytest。pytest 设计可以运行 unittest 测试,迁移成本比你想象的低。我曾经在一个项目里直接把 unittest 测试文件放在 pytest 环境下跑,除了需要调整一些 import 路径,基本没改代码。

什么时候选 unittest?

  • 项目不允许安装第三方库(比如某些运维严格的封闭系统)
  • 团队成员对 JUnit 风格很熟,不想改变习惯
  • 只做单元测试,不需要复杂的夹具或参数化
  • 公司强制只能使用标准库(我见过这种奇葩规定)

什么时候选 pytest?

  • 需要频繁编写集成测试,尤其是涉及数据库、API、文件系统
  • 测试数据多,需要参数化,比如测同一个接口的不同输入
  • 需要并行执行测试,减少 CI 流水线时间
  • 想提高测试代码的可读性和维护性

我的建议:如果现在让我重新选,只要不是受限于标准库,我会毫不犹豫用 pytest。它社区的插件质量很高,比如 pytest-xdist 可以并行跑测试,pytest-cov 可以生成代码覆盖率报告。尤其是集成测试,数据准备和清理的工作量很大,pytest 的 fixture 能把这些逻辑抽出来,不用在每个测试里重复写。

一个决策思路

你可能还在纠结。没关系,我给你画了一张简单的判断图。选不好框架,可以用这张图一步步决策。

测试框架选择流程图 开始选择测试框架 第三方库可以安装吗? 否(受限环境) 选择 unittest 是(可自由安装) 团队更熟悉 JUnit 风格? 且不做集成测试 也可以 unittest 否(需要灵活集成测试) 选择 pytest pytest 可以运行 unittest 测试,迁移成本低 优先考虑 pytest,除非环境受限

说到底,选择框架不只是技术问题,还有团队习惯和项目约束。我见过有的项目组全员用 unittest,代码风格统一,维护起来也顺畅。反过来,如果团队灵活,想做集成测试自动化,pytest 的生态会让你事半功倍。

在实际项目中,unittest 和 pytest 并不完全互斥。你可以在一个大项目里,旧的测试模块继续用 unittest 维护,新写的集成测试用 pytest。两者并存一段时间,等有精力了再逐步迁移。这个思路我在之前一个支付系统项目里用过,效果不错。

一句话总结:选 pytest,你得到的是更快的开发节奏和更好的测试报告;选 unittest,你得到的是零依赖的稳定。但别被选择困住——可以先从 pytest 学起,毕竟它能直接跑 unittest 测试。