Unittest与Pytest核心差异解析 | AI生成和翻译

Home 2025.09

以下是一份简洁明了的对比,重点关注日常测试中实际发生的变化。

理念与风格

测试发现

断言

Fixture 与设置

参数化

跳过、预期失败与标记

插件与生态系统

Mock

异步测试

性能与并行

IDE/CI/覆盖率

如何选择

互操作与迁移

你可以在 pytest 下运行 unittest 测试套件(pytest 能发现 unittest.TestCase)。这使你可以逐步迁移:

  1. 开始使用 pytest 作为运行器。
  2. 在现有测试旁添加 pytest 测试。
  3. 在需要的地方引入 fixture/参数化。
  4. 后续可选择将旧的 TestCase 重构为函数。

小型对比示例

相同的测试

unittest

import unittest

class TestMath(unittest.TestCase):
    def setUp(self):
        self.data = [1, 2, 3]

    def test_sum(self):
        self.assertEqual(sum(self.data), 6)

    def test_raises(self):
        with self.assertRaises(ZeroDivisionError):
            1 / 0

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

pytest

import pytest

@pytest.fixture
def data():
    return [1, 2, 3]

def test_sum(data):
    assert sum(data) == 6

def test_raises():
    with pytest.raises(ZeroDivisionError):
        1 / 0

参数化

unittest (subTest)

import unittest

class TestParity(unittest.TestCase):
    def test_even(self):
        for n in [0, 2, 4]:
            with self.subTest(n=n):
                self.assertEqual(n % 2, 0)

pytest

import pytest

@pytest.mark.parametrize("n", [0, 2, 4])
def test_even(n):
    assert n % 2 == 0

Mocking

unittest.mock

from unittest.mock import patch

@patch("pkg.api.fetch_user", return_value={"id": 1})
def test_uses_api(mock_fetch):
    from pkg.service import get_user
    assert get_user(1)["id"] == 1
    mock_fetch.assert_called_once_with(1)

pytest-mock

def test_uses_api(mocker):
    mock_fetch = mocker.patch("pkg.api.fetch_user", return_value={"id": 1})
    from pkg.service import get_user
    assert get_user(1)["id"] == 1
    mock_fetch.assert_called_once_with(1)

实用建议

如果你愿意,告诉我你的项目结构和约束(仅限标准库?需要并行?异步?Django/Flask/FastAPI?),我可以为你设计一个最小化且实用的测试设置方案。


Back Donate