Python中的assert用法

Python中的assert用法

本文转载自Python中不尽如人意的断言Assertion,如有侵权,立马删除!

使用assert断言是学习Python一个非常好的习惯,Python assert 断言 语句格式及用法很简单;在没完善一个程序之前,我们不知道程序在哪里会出错,与其让它在运行时崩溃,不如在出现错误条件时就崩溃,这时候就需要assert断言的帮助;本文主要是将assert断言的基础知识。

Python assert 断言的作用

Python assert 断言是声明其布尔值必须为真的判定,如果发生异常就说明表达式为假。可以理解 assert断言语句为raise-if-not,用来测试表达式,其返回值为假,就会触发异常。

assert 断言语句的语法格式

assert Python怎么用?

expression assert 表达式

下面做一些assert用法的语句供参考:

assert 1==1
assert 2+2 == 2*2
assert len(['my boy', 12]) < 10
assert range(4) == [0,1,2,3]

如何为assert断言语句添加异常参数

assert的异常参数,其实就是在断言表达式后添加字符串信息,用来解释断言并更好的知道是哪里出了问题。格式如下:

assert expression[,arguments]
assert 表达式[,参数]
assert len(lists) >= 5, '列表元素个数小于5'
assert 2 == 1, '2不等于1'

Python assert 为何不尽如人意

Python中的断言用起来非常简单,你可以在assert后面跟上人意判断条件,如果断言失败则会抛出异常。

assert 1+1 == 2
assert isinstance('Hello', str)
assert isinstance('Hello', int)

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

其实assert看上去不错,然而用起来并不友好;就比如有人告诉你程序错了,但是不告诉哪里错了;很多时候这样的assert还不如不写;直接抛一个异常会更好一些。

改进方案 #1

s = 'nothin is impossible.'
key = 'nothing'
assert key in s, "key: '{}' is not in Target: '{}'".format(key, s)

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: key: 'nothing' is not int Target: 'nothin is impossible.'

看上去还行,但是其实很是有点不友好;假如你是一名测试员,有成千上万的测试案例需要做断言做验证,这样的做法就不适用了。

改进方案 #2

不管你是做测试还是开发的,想必听过不少测试框架;

py.test

py.test 是一个轻量级的测试框架,所以它压根就没写自己的断言系统,但是它对Python自带的断言做了强化处理,如果断言失败,那么框架本身会尽可能多地提供断言失败的原因。那么也就意味着,用py.test实现测试,你一行代码都不用改。

import pytest
def test_case():
	expected = 'Hello'
	actual = 'hello'
	assert expected == actual
	
if __name__ == '__main__':
	pytest.main()

执行结果如下:

============================= test session starts =============================
platform win32 -- Python 3.7.1, pytest-4.4.1, py-1.8.0, pluggy-0.9.0
rootdir: E:\Python5\newmallpro\TestAPI
collected 0 items / 1 errors

=================================== ERRORS ====================================
________________________ ERROR collecting test_one.py _________________________
ImportError while importing test module 'E:\Python5\newmallpro\TestAPI\test_one.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
test_one.py:10: in <module>
    import requests
E   ModuleNotFoundError: No module named 'requests'
!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!
=========================== 1 error in 0.14 seconds ===========================
unittest(单元测试)

Python自带的unittest单元测试框架就有了自己的断言方法self.assertXXX(),而且不推荐使用assert XXX语句。

import unittest


class TestStringMethods(unittest.TestCase):

    def test_upper(self):
        self.assertEqual('foo'.upper(), 'FoO')


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

执行结果如下:

FoO != FOO

Expected :FOO
Actual   :FoO
 <Click to see difference>

Traceback (most recent call last):
  File "D:\appinstallation\pycharminstall\PyCharm 2018.3.1\helpers\pycharm\teamcity\diff_tools.py", line 32, in _patched_equals
    old(self, first, second, msg)
  File "D:\appinstallation\pythonInstall\lib\unittest\case.py", line 839, in assertEqual
    assertion_func(first, second, msg=msg)
  File "D:\appinstallation\pythonInstall\lib\unittest\case.py", line 1220, in assertMultiLineEqual
    self.fail(self._formatMessage(msg, standardMsg))
  File "D:\appinstallation\pythonInstall\lib\unittest\case.py", line 680, in fail
    raise self.failureException(msg)
AssertionError: 'FOO' != 'FoO'
ptest

ptest中的断言可读性很好,而且智能提示也很方便你通过IDE轻松完成各种断言语句。感谢Karl大神写了这个一个测试框架。

from ptest.decorator import *
from ptest.assertion import *


@TestClass()
class TestCases:
    @Test()
    def test1(self):
        actual = 'foo'
        expected = 'bar'
        assert_that(expected).is_equal_to(actual)


if __name__ == '__main__':
    TestCases().test1()

执行结果如下:

AssertionError: Unexpectedly that the str <bar> is not equal to str <foo>.

改进方案 #3

很多人对Python中的断言表示不满足,所以大家都争相发明自己的assert包。在这里我强烈推荐assertpy这个包,

它异常强大而且好评如潮。

pip install assertpy

代码示例:

from assertpy import assert_that


def test_something():
    assert_that(1 + 2).is_equal_to(3)
    assert_that('foobar').is_length(6).starts_with('foo').ends_with('bar')
    assert_that(['a', 'b', 'c']).contains('a').does_not_contain('x')
    assert_that('a').is_length(4)


if __name__ == '__main__':
    test_something()

执行结果如下:

AssertionError: Expected <a> to be of length <4>, but was <1>.

从他的github 主页文档上你会发现它支持了几乎你能想到的所有所有测试场景,包括但不限于一下列表:

  • Strings
  • Numbers
  • Lists
  • Tuples
  • Dicts
  • Sets
  • Booleans
  • Dates
  • Fiels
  • Objects

而且它的断言信息简洁明了,不多不少。

Expected <foo> to be of length <4>, but was <3>.
Expected <foo> to be empty string, but was not.
Expected <False>, but was not.
Expected <foo> to contain only digits, but did not.
Expected <123> to contain only alphabetic chars, but did not.
Expected <foo> to contain only uppercase chars, but did not.
Expected <FOO> to contain only lowercase chars, but did not.
Expected <foo> to be equal to <bar>, but was not.
Expected <foo> to be not equal to <foo>, but was.
Expected <foo> to be case-insensitive equal to <BAR>, but was not.

总结

断言在软件中有非常重要的作用,写的好可以让你的系统更稳定,也可以让你有更多真正面对对象的时间,而不是在调试代码。

Python中默认的断言语句其实还有一个作用,如果你写了一个类型相关的断言,IDE会把这个对象当成这种类型,这时候智能提示就有如神助。

要不要把内置的断言语句换成可读性更好功能更强大的第三方断言,完全取决于实际情况。比如你真的需要验证某个东西并且很关心验证结果,那么必须不能用简单的assert;如果你只是担心某个点可能有坑或者让IDE认识某个对象,用内置的assert既简单又方便。

本文转载自Python中不尽如人意的断言Assertion,如有侵权,立马删除!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值