Unittest 和 Doctest 之间的区别

2024 年 8 月 29 日 | 5 分钟阅读

在本教程中,我们将讨论 doctest 和 unittest 之间的区别,并看一些案例。测试是软件开发的重要阶段,它有助于识别错误、编写敏捷代码和实现代码重用。通过对代码库进行多个测试用例的测试,可以防止其出现故障并最大限度地减少漏洞的暴露。Python 提供了两个主要的测试框架:doctest 和 unittest。让我们熟悉一下这两个框架。

Doctest 简介

Doctest 是一个内置框架,这意味着它随 Python 一起安装,无需单独安装。doctest 模块用于识别和执行模仿交互式 Python 会话的代码片段,并测试以确保结果与描述中的预期输出相匹配。doctest 最常用于测试文档。它会检查 docstring 中的语句序列,重新执行提取的命令,并将其与 docstring 中的命令行输入进行比较。默认情况下,在使用 doctest 模块时,测试用例通过时不会显示输出。但是,可以通过 doctest runner 中的选项来更改此行为。此外,doctest 与 Python unittest 框架的兼容性允许我们将 doctest 作为常规的 unittest 测试用例执行。如果您想了解更多关于 doctest 模块的信息,可以查看我们的Python Doctest 模块教程。

Unittest 简介

unittest 中的测试运行器在执行测试用例时提供了其他选项,包括生成关于结果的统计报告的能力,其中包含通过和失败的测试用例数量。在 unittest 中,类中创建的方法管理测试。它支持测试时的设置、自动化和关闭代码。它附带了各种内置的丰富功能,包括 doctest 中未包含的生成器和组夹具管理器。

由于 unittest 遵循面向对象的方法,因此它更适合在非生产环境中测试基于类的代码。另一方面,Jenkins 或 Travis CI 等持续交付工具更适合生产环境。在接下来的部分中,我们将演示一个处理员工信息及其对工资的影响的真实代码示例,并使用 doctest 和 unittest 进行测试。在进行测试后,我们将评估结果并提出进一步改进测试过程的方法。

代码示例 - 使用 Unittest

让我们实现 Employee 类,并创建一些方法来使用 unittest 进行测试。让我们看下面的代码。

示例 -

在上面的代码中,我们从 Python 包导入 unittest,并导入 Employee 类。在 TestEmployee 类中,我们使用 unittest 中的 "TestCase",因为它允许我们为每组输入验证特定的输出。然后,我们使用以 "test" 前缀开头的方法设计三个独立的测试。"test" 前缀会向测试运行器发出信号,指示要将哪些方法作为测试运行。

test_employee.py

在上面的代码中,我们从 Python 包导入 unittest,并导入 Employee 类。在 TestEmployee 类中,我们使用 unittest 中的 "TestCase",因为它为我们提供了为每组输入验证特定输出的能力。然后,我们使用以 "test" 前缀开头的方法设计三个独立的测试。"test" 前缀会向测试运行器发出信号,指示要将哪些方法作为测试运行。

setUp() 方法在任何其他测试方法执行之前执行,我们在这里创建客户实例。我们使用 assert() 方法中的 assertEqual() 方法来比较每个测试方法中的预期结果和实际结果。当我们运行上面的测试时,我们得到以下结果。

...
----------------------------------------------------------------------
Ran 3 tests in 0.001s
OK

如果我们更改预期输出,我们将看到以下结果。

C:\Users\User\Desktop\my_project\unittest>python test_employee.py
F..
======================================================================
FAIL: test_apply_epf (__main__.TestEmployee)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test_employee.py", line 22, in test_apply_epf
    self.assertEqual(self.employee_1.salary, 47500)
AssertionError: 475000 != 47500

----------------------------------------------------------------------
Ran 3 tests in 0.001s

FAILED (failures=1)

这种类型的测试可以快速识别错误,并帮助精确定位代码中发生错误的位置。通过利用 unittest 并创建涵盖所有可能场景的测试,我们可以增强程序的清晰度、功能性和逻辑流程。

使用 Doctest

与 unittest 相比,使用 doctest 更简单,步骤更少。尽管易于使用,但在使用 doctest 时要格外小心,因为它存在一些限制。

现在,让我们使用 doctest 来演示前面的示例。

示例 -

现在,我们将在终端中执行以下操作。

我们在终端中运行 python doctest_employee -v 命令,它返回以下输出。

输出 -

Trying:
    employee_1 = Employee("John", "Brad", 5000)
Expecting nothing
ok
Trying:
    employee_2 = Employee("Tina", "Smith", 3000)
Expecting nothing
ok
Trying:
    employee_1.employee_mail()
Expecting:
    '[email protected]'
ok
Trying:
    employee_2.employee_mail()
Expecting:
    '[email protected]'
ok
Trying:
    employee_1.employee_fullname()
Expecting:
    'John Brad'
ok
Trying:
    employee_2.employee_fullname()
Expecting:
    'Tina Smith'
ok
Trying:
    employee_1.apply_epf()
Expecting:
    4750
ok
Trying:
    employee_2.apply_epf()
Expecting:
    2850
ok
5 items had no tests:
    __main__
    __main__.employee.__init__
    __main__.employee.apply_epf
    __main__.employee.employee_fullname
    __main__.employee.employee_mail
1 items passed all tests:
   8 tests in __main__.employee
8 tests in 6 items.
8 passed and 0 failed.
Test passed.

如上输出所示,所有测试都通过了。doctest 为编写包的可执行文档提供了简单而合适的方法,而 unittest 则更适合测试文档。

结论

本教程介绍了 doctest 和 unittest 之间的区别。unittest 框架提供了一种面向对象的方法来测试代码,包括自动化、设置和拆卸测试代码等功能。另一方面,doctest 更适合文档,因为它嵌入在代码的 docstrings 中。