在 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