在 Python 中斷言 equal
在構建軟體時,我們需要使用程式碼來實現業務邏輯。
為了確保我們實現所有邏輯和約束,我們在程式中使用了 assert 語句。在大型應用程式中,我們藉助 Python 中的 assertEquals()
和 assertEqual()
方法使用單元測試。
我們將討論斷言語句
在 Python 中是如何工作的。我們還將看到如何使用 assertEquals()
和 assertEqual()
方法在 Python 中實現業務邏輯和約束。
什麼是 Python 中的斷言語句
在 Python 中,assert 語句檢查表示式是 True
還是 False
。assert 語句的語法如下。
assert conditional_expression
這裡,assert
是關鍵字。conditional_expression
是一個條件語句,將語句評估為 True
或 False
。
如果 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.
/usr/lib/python3/dist-packages/requests/__init__.py:89: RequestsDependencyWarning: urllib3 (1.26.7) or chardet (3.0.4) doesn't match a supported version!
warnings.warn("urllib3 ({}) or chardet ({}) doesn't match a supported "
Traceback (most recent call last):
File "/home/aditya1117/PycharmProjects/pythonProject/string1.py", line 7, 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.
/usr/lib/python3/dist-packages/requests/__init__.py:89: RequestsDependencyWarning: urllib3 (1.26.7) or chardet (3.0.4) doesn't match a supported version!
warnings.warn("urllib3 ({}) or chardet ({}) doesn't match a supported "
Traceback (most recent call last):
File "/home/aditya1117/PycharmProjects/pythonProject/string1.py", line 7, 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()
。在這裡,我們在名稱 condition1
和 condition2
之前包含 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 程式語言中棄用。