在 Python 中断言 equal

Aditya Raj 2023年1月30日
  1. 什么是 Python 中的断言语句
  2. Python 中的 assertEquals() 方法
  3. Python 中的 assertEqual() 方法
  4. 结论
在 Python 中断言 equal

在构建软件时,我们需要使用代码来实现业务逻辑。

为了确保我们实现所有逻辑和约束,我们在程序中使用了 assert 语句。在大型应用程序中,我们借助 Python 中的 assertEquals()assertEqual() 方法使用单元测试。

我们将讨论断言语句在 Python 中是如何工作的。我们还将看到如何使用 assertEquals()assertEqual() 方法在 Python 中实现业务逻辑和约束。

什么是 Python 中的断言语句

在 Python 中,assert 语句检查表达式是 True 还是 False。assert 语句的语法如下。

assert conditional_expression

这里,assert 是关键字。conditional_expression 是一个条件语句,将语句评估为 TrueFalse

如果 condition_expression 的计算结果为 True,程序的执行将前进到下一条语句。另一方面,如果 conditional_expression 的计算结果为 False,程序将引发 AssertionError 异常。

我们可以在下面看到所有这些。

num1 = 10
num2 = 5
num3 = 10
print("This statement will get printed")
assert num1 == num3
print(
    "This statement will also get printed as the expression in the above assert statement is True."
)
assert num2 == num3
print(
    "This statement will not get printed as the expression in the above assert statement is False. This line of code is unreachable."
)

输出:

This statement will get printed
This statement will also get printed as the expression in the above assert statement is True.

Traceback (most recent call last):
  File "tempy.py", line 9, in <module>
    assert num2 == num3
AssertionError

在这里,你可以观察到第一个打印语句是自动执行的。

语句 assert num1 == num3 不会引发错误,因为 10==10 的计算结果为 True。因此,第二个打印语句也被执行。

之后,语句 "assert num2 == num3" 引发 AssertionError,因为 5==10 评估为 False。因此,程序执行停止,第三个打印语句永远不会执行。

我们还可以在发生 AssertionError 异常时显示一条消息。为此,我们将使用以下语法。

assert conditional_expression, message

这里,message 是一个字符串,当 conditional_expression 评估为 False 并且发生 AssertionError 时打印。我们可以在下面看到这一点。

num1 = 10
num2 = 5
num3 = 10
print("This statement will get printed")
assert num1 == num3, "{} is not equal to {}".format(num1, num2)
print(
    "This statement will also get printed as the expression in the above assert statement is True."
)
assert num2 == num3, "{} is not equal to {}".format(num2, num3)
print(
    "This statement will not get printed as the expression in the above assert statement is False. This line of code is unreachable."
)

输出:

This statement will get printed
This statement will also get printed as the expression in the above assert statement is True.

Traceback (most recent call last):
  File "tempy.py", line 9, in <module>
    assert num2 == num3, "{} is not equal to {}".format(num2, num3)
AssertionError: 5 is not equal to 10

在通知 AssertionError 后也会打印输出 5 is not equal to 10。包含这些类型的消息将帮助你更轻松地测试程序的功能,因为你可以在出现 AssertionError 异常时使用消息通知需求。

我们可以使用 assert 语句来强制执行约束或在 Python 中实现业务逻辑。但是,使用 assert 语句有一个缺点:一旦 assert statement 中的条件语句计算为 False,它会停止程序的执行。

因此,在具有数千个约束和条件的大型程序中,我们将不得不执行程序的次数与 AssertionError 异常发生的次数一样多。

为了克服这个问题,我们可以使用前面讨论的 assertEquals()assertEqual() 语句。

Python 中的 assertEquals() 方法

为了在软件中强制执行约束和业务逻辑,我们可以使用 unittest 模块。

unittest 模块为我们提供了许多可以用来强制约束的方法。为了实现相等的断言,我们可以使用 assertEquals() 方法和 assertEqual() 方法。

为了使用 assertEquals() 方法实现相等断言,我们将首先创建一个类,它是 unittest 模块中定义的 TestCase 类的子类。然后,我们可以使用 assertEquals() 方法的以下语法定义相等的断言。

self.assertEquals(self, first, second)

这里,参数 first 接受第一个值作为输入参数。参数 second 接受第二个值作为输入参数。

如果参数 first 等于参数 second 中的值,则单元测试将成功通过。否则,会在当前行引发 AssertionError 异常,并通知用户该错误。

因此,测试用例失败了,但程序的执行并没有像在 assert 语句的情况下那样停止。程序运行所有测试用例,然后将所有错误通知开发人员。

我们可以在下面看到这一点。

import unittest


class Tester(unittest.TestCase):
    def setUp(self):
        self.num1 = 10
        self.num2 = 5
        self.num3 = 10

    def tearDown(self):
        print("\nTest case completed. Result:")

    def test_condition1(self):
        self.assertEquals(self.num1, self.num3)

    def test_condition2(self):
        self.assertEquals(self.num2, self.num3)


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

输出:

/home/aditya1117/PycharmProjects/pythonProject/webscraping.py:14: DeprecationWarning: Please use assertEqual instead.
  self.assertEquals(self.num1, self.num3)
.F
======================================================================
FAIL: test_condition2 (__main__.Tester)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/aditya1117/PycharmProjects/pythonProject/webscraping.py", line 17, in test_condition2
    self.assertEquals(self.num2, self.num3)
AssertionError: 5 != 10

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)

Test case completed. Result:

Test case completed. Result:

这里,当执行 unittest.main() 方法时,会创建 Tester 类的实例。之后,执行 setUp() 方法。setUp() 方法初始化变量并将值从其他模块导入 Tester 类。

你还可以观察到我们已经实现了方法 test_condition1()test_condition2()。在这里,我们在名称 condition1condition2 之前包含 test_,以使解释器了解这些方法正在用于执行测试用例。

如果我们不指定以 test_ 开头的方法名称,该方法将不会被 python 解释器执行。

tearDown() 方法在每个测试用例之后执行。你可以使用此方法重新初始化变量和其他值。

执行完所有测试用例后,结果显示一个测试用例失败。我们还可以在每次 assertEquals() 方法引发 AssertionError 异常(即测试用例失败)时打印一条可选消息。

为此,我们必须将消息字符串作为第三个输入参数传递给 assertEquals() 方法,如下所示。

import unittest


class Tester(unittest.TestCase):
    def setUp(self):
        self.num1 = 10
        self.num2 = 5
        self.num3 = 10

    def tearDown(self):
        print("\nTest case completed. Result:")

    def test_condition1(self):
        message = "{} is not equal to {}".format(self.num1, self.num3)
        self.assertEquals(self.num1, self.num3, message)

    def test_condition2(self):
        message = "{} is not equal to {}".format(self.num2, self.num3)
        self.assertEquals(self.num2, self.num3, message)


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

输出:

Test case completed. Result:

Test case completed. Result:
/home/aditya1117/PycharmProjects/pythonProject/webscraping.py:15: DeprecationWarning: Please use assertEqual instead.
  self.assertEquals(self.num1, self.num3,message)
.F
======================================================================
FAIL: test_condition2 (__main__.Tester)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/aditya1117/PycharmProjects/pythonProject/webscraping.py", line 19, in test_condition2
    self.assertEquals(self.num2, self.num3,message)
AssertionError: 5 != 10 : 5 is not equal to 10

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)

在这里,你可以观察到,当第二个测试用例失败时,解释器还会打印消息 5 is not equal to 10

assertEquals() 方法已于 2010 年弃用。因此,在使用 assertEquals() 方法时,你将收到一条警告,指出该方法已被弃用,并显示一条消息 DeprecationWarning: Please use assertEqual instead

正如 Python 建议我们使用 assertEqual() 方法,让我们用它来实现 Python 中的相等断言。

Python 中的 assertEqual() 方法

除了名称中的 s 外,assertEqual() 方法的工作原理与 assertEquals() 方法完全相似。两种方法的语法也相同。

因此,你可以使用 assertEqual() 方法代替 assertEquals() 方法,如下所示。

import unittest


class Tester(unittest.TestCase):
    def setUp(self):
        self.num1 = 10
        self.num2 = 5
        self.num3 = 10

    def tearDown(self):
        print("\nTest case completed. Result:")

    def test_condition1(self):
        self.assertEqual(self.num1, self.num3)

    def test_condition2(self):
        self.assertEqual(self.num2, self.num3)


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

输出:

.F
======================================================================
FAIL: test_condition2 (__main__.Tester)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/aditya1117/PycharmProjects/pythonProject/webscraping.py", line 17, in test_condition2
    self.assertEqual(self.num2, self.num3)
AssertionError: 5 != 10

----------------------------------------------------------------------
Ran 2 tests in 0.000s

FAILED (failures=1)

Test case completed. Result:

Test case completed. Result:

Process finished with exit code 1

在输出中,我们可以观察到程序的工作方式与前面的代码相同。此外,我们还没有收到任何有关折旧的警告。

你可以按如下方式向测试用例添加消息。

import unittest


class Tester(unittest.TestCase):
    def setUp(self):
        self.num1 = 10
        self.num2 = 5
        self.num3 = 10

    def tearDown(self):
        print("\nTest case completed. Result:")

    def test_condition1(self):
        message = "{} is not equal to {}".format(self.num1, self.num3)
        self.assertEqual(self.num1, self.num3, message)

    def test_condition2(self):
        message = "{} is not equal to {}".format(self.num2, self.num3)
        self.assertEqual(self.num2, self.num3, message)


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

输出:

.F
======================================================================
FAIL: test_condition2 (__main__.Tester)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/aditya1117/PycharmProjects/pythonProject/webscraping.py", line 19, in test_condition2
    self.assertEqual(self.num2, self.num3, message)
AssertionError: 5 != 10 : 5 is not equal to 10

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)

Test case completed. Result:

Test case completed. Result:

在本文中,你可以观察到我们已经实现了 unittest 模块中定义的 TestCase 类的子类,以使用 assertEquals() 方法和 assertEqual() 方法。

在使用 Django 框架开发程序时,你最终可能会实现 Django.test 模块中定义的 TestCase 类的子类。这种情况下程序会出现错误,如下图。

import unittest
from django.test import TestCase


class Tester(TestCase):
    def setUp(self):
        self.num1 = 10
        self.num2 = 5
        self.num3 = 10

    def tearDown(self):
        print("\nTest case completed. Result:")

    def test_condition1(self):
        message = "{} is not equal to {}".format(self.num1, self.num3)
        self.assertEqual(self.num1, self.num3, message)

    def test_condition2(self):
        message = "{} is not equal to {}".format(self.num2, self.num3)
        self.assertEqual(self.num2, self.num3, message)


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

输出:

E
======================================================================
ERROR: setUpClass (__main__.Tester)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/test/testcases.py", line 1201, in setUpClass
    super().setUpClass()
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/test/testcases.py", line 187, in setUpClass
    cls._add_databases_failures()
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/test/testcases.py", line 209, in _add_databases_failures
    cls.databases = cls._validate_databases()
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/test/testcases.py", line 195, in _validate_databases
    if alias not in connections:
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/utils/connection.py", line 73, in __iter__
    return iter(self.settings)
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/utils/functional.py", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/utils/connection.py", line 45, in settings
    self._settings = self.configure_settings(self._settings)
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/db/utils.py", line 144, in configure_settings
    databases = super().configure_settings(databases)
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/utils/connection.py", line 50, in configure_settings
    settings = getattr(django_settings, self.settings_name)
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/conf/__init__.py", line 84, in __getattr__
    self._setup(name)
  File "/home/aditya1117/.local/lib/python3.8/site-packages/django/conf/__init__.py", line 65, in _setup
    raise ImproperlyConfigured(
django.core.exceptions.ImproperlyConfigured: Requested setting DATABASES, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.

----------------------------------------------------------------------
Ran 0 tests in 0.003s

FAILED (errors=1)

在这里,你可以观察到,当我们使用 django.test 模块中的 TestCase 类时,程序会出错。因此,不执行任何测试用例。

因此,请确保你始终使用在 unittest 模块中定义的 TestCase 类,而不是在 Django.test 模块中。

结论

我们讨论了使用 assert 语句、assertEquals()assertEqual() 方法来测试我们的应用程序。

在这里,如果你记得 assert 语句和 assertEqual() 方法在生产环境中的实际应用程序中无法使用,那将会有所帮助。在生产环境中部署代码之前,你只能使用这些方法来测试你的应用程序。

此外,请确保你使用 assertEqual() 方法而不是 assertEquals() 方法,因为后者已从 python 编程语言中弃用。

作者: Aditya Raj
Aditya Raj avatar Aditya Raj avatar

Aditya Raj is a highly skilled technical professional with a background in IT and business, holding an Integrated B.Tech (IT) and MBA (IT) from the Indian Institute of Information Technology Allahabad. With a solid foundation in data analytics, programming languages (C, Java, Python), and software environments, Aditya has excelled in various roles. He has significant experience as a Technical Content Writer for Python on multiple platforms and has interned in data analytics at Apollo Clinics. His projects demonstrate a keen interest in cutting-edge technology and problem-solving, showcasing his proficiency in areas like data mining and software development. Aditya's achievements include securing a top position in a project demonstration competition and gaining certifications in Python, SQL, and digital marketing fundamentals.

GitHub