在 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 编程语言中弃用。