Python断言教程展示了如何在Python中使用断言。我们定义断言,解释断言和异常之间的区别,并展示它们与单元测试的关系。
断言
断言是代码中的内部自检;它们适合开发人员尽快发现错误。断言的目的是在程序的早期检测问题,原因很清楚,并避免它们作为其他操作的副作用弹出。
断言不应该用于数据处理或验证,因为它们在生产中被关闭。一些编程语言,例如Go,不使用断言。其他语言也有assert语句,但很少使用(Java)。
断言与异常
断言是布尔表达式,必须为真才能使代码正确。断言失败会导致代码更正。异常是关于可能在运行时发生的非典型情况的指示。异常可能不会导致代码中缀。例如,如果Internet连接中断,或文件权限不足,则用户必须进行处理。断言不应用于处理运行时错误。
按合同设计
按合同设计或按合同编程是一种软件开发实践,开发人员在其中为软件组件定义正式、精确和可验证的接口规范。规范分为前置条件、后置条件和不变量。
先决条件是在执行一段代码之前必须始终为真的谓词。poscondition是一个谓词,在执行一段代码后必须始终为真。不变量是在所有操作之后保持不变的属性。
合同设计方法是在1980年代发展起来的,受到商业合同的启发。
断言和单元测试
断言和单元测试在某些方面有重叠,但也存在一些差异。断言是对程序内部状态的假设,而单元测试检查模块的外部行为。单元测试使用测试数据,而断言则不行。
断言语句用于单元测试。经典断言是关于真实情况的假设,而在单元测试中,开发人员经常测试错误条件。
Python断言
assert语句是将调试断言插入Python程序的便捷方式。使用-O、-OO选项和PYTHONOPTIMIZE变量删除断言语句。
Pythonassert语句由一个布尔条件和一个可选的错误消息组成,以逗号分隔。
Python断言示例
以下示例展示了Pythonassert语句的用法。
#!/usr/bin/python
def info(age, name):
assert age >= 18 and age <= 65, 'age value must be between values 18 and 65'
print(f'{name} is {age} years old')
age = 84
name = 'Peter'
info(age, name)
在这个例子中,我们有一个关于年龄值的先决条件。
$ ./precondition.py
Traceback (most recent call last):
File "./precondition.py", line 14, in <module>
info(age, name)
File "./precondition.py", line 6, in info
assert age >= 18 and age <= 65, 'age value must be between values 18 and 65'
AssertionError: age value must be between values 18 and 65
程序失败,因为前提条件无效。
#!/usr/bin/python
def do_discount(price, discount):
discounted_price = price - discount * price
assert 0 < discounted_price < price, 'discounted price must be greater than zero and lower than original price'
return discounted_price
price = 120
discount = 0.2
dis_price = do_discount(price, discount)
print(dis_price)
第二个例子有一个关于折扣价的后置条件。它必须大于零且低于原始价格。
单元测试中的Python断言
Python有几个流行的单元测试框架,包括pytest、unittest和nose。虽然pytest和nose使用assert语句,但unittest支持assertEqual等函数和assertLess。
Pytest示例
下面的例子展示了pytest框架的使用。
def max(values):
_max = values[0]
for val in values:
if val > _max:
_max = val
return _max
def min(values):
_min = values[0]
for val in values:
if val < _min:
_min = val
return _min
我们在一个模块中有两个算法。
#!/usr/bin/python
import algo
def test_min():
values = (2, 3, 1, 4, 6)
val = algo.min(values)
assert val == 1
def test_max():
values = (2, 3, 1, 4, 6)
val = algo.max(values)
assert val == 6
我们将测试数据传递给被测试的algo函数。我们使用assert语句检查预期值。
$ pytest-3 min_max_test.py ============================================================= test session starts ============================================================= platform linux -- Python 3.7.6, pytest-4.6.9, py-1.8.1, pluggy-0.13.0 rootdir: /root/Documents/prog/python/assert collected 2 items min_max_test.py ..
我们运行测试。
单元测试示例
现在我们用unittest测试同一个模块。
#!/usr/bin/python
import unittest
import algo
class SimpleTest(unittest.TestCase):
def test_min(self):
values = (2, 3, 1, 4, 6)
val = algo.min(values)
self.assertEqual(val, 1)
def test_max(self):
values = (2, 3, 1, 4, 6)
val = algo.max(values)
self.assertEqual(val, 6)
if __name__ == '__main__':
unittest.main()
在示例中,我们使用了assertEqual断言。
$ ./min_max_test.py .. ---------------------------------------------------------------------- Ran 2 tests in 0.000s OK
我们运行测试。
在本教程中,我们使用了Pythonassert语句并大体解释了断言。
列出所有Python教程。
