Python中断言Assertion的一些改进方案


Posted in Python onOctober 27, 2016

Python Assert 为何不尽如人意?

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

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

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

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

改进方案 #1

一个稍微改进一丢丢的方案就是把必要的信息也放到assert语句后面,比如这样。

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

Traceback (most recent call last):
 File "<input>", line 1, in <module>
AssertionError: Key: 'nothing' is not in 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()

"""
================================== FAILURES ===================================
__________________________________ test_case __________________________________

  def test_case():
    expected = "Hello"
    actual = "hello"
>    assert expected == actual
E    assert 'Hello' == 'hello'
E     - Hello
E     ? ^
E     + hello
E     ? ^

assertion_in_python.py:7: AssertionError
========================== 1 failed in 0.05 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()
  
"""
Failure
Expected :'FOO'
Actual  :'FoO'

Traceback (most recent call last):
 File "assertion_in_python.py", line 6, in test_upper
  self.assertEqual('foo'.upper(), 'FoO')
AssertionError: 'FOO' != 'FoO'
"""

ptest

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

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)

"""
Start to run following 1 tests:
------------------------------
...
[demo.assertion_in_python.TestCases.test1@Test] Failed with following message:
...
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')

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

      Strings

      Numbers

      Lists

      Tuples

      Dicts

      Sets

      Booleans

      Dates

      Files

      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.

在发现assertpy之前我也想写一个类似的包,尽可能通用一些。但是现在,我为毛要重新去造轮子?完全没必要!

总结

断言在软件系统中有非常重要的作用,写的好可以让你的系统更稳定。Python中默认的断言语句其实还有一个作用,如果你写了一个类型相关的断言,IDE会把这个对象当成这种类型,这时候智能提示就有如神助。

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

所以说,项目经验还是蛮重要的。以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能有所帮助,如果有疑问大家可以留言交流。

Python 相关文章推荐
详解Python编程中time模块的使用
Nov 20 Python
Python中的浮点数原理与运算分析
Oct 12 Python
手把手教你python实现SVM算法
Dec 27 Python
Python3实现的画图及加载图片动画效果示例
Jan 19 Python
Python使用wxPython实现计算器
Jan 30 Python
python实现类之间的方法互相调用
Apr 29 Python
对Tensorflow中的变量初始化函数详解
Jul 27 Python
python使用Matplotlib画饼图
Sep 25 Python
python爬虫获取百度首页内容教学
Dec 23 Python
基于python监控程序是否关闭
Jan 14 Python
Python的pygame安装教程详解
Feb 10 Python
Jupyter notebook 不自动弹出网页的解决方案
May 21 Python
利用Python实现颜色色值转换的小工具
Oct 27 #Python
Python实现批量检测HTTP服务的状态
Oct 27 #Python
python解决网站的反爬虫策略总结
Oct 26 #Python
Python控制多进程与多线程并发数总结
Oct 26 #Python
Python网络爬虫项目:内容提取器的定义
Oct 25 #Python
Python实现ssh批量登录并执行命令
Oct 25 #Python
详解Python的Lambda函数与排序
Oct 25 #Python
You might like
《超神学院》霸气归来, 天使彦上演维多利亚的秘密
2020/03/02 国漫
利用php来自动调用不同服务器上的flash
2006/10/09 PHP
PHP个人网站架设连环讲(三)
2006/10/09 PHP
php计算十二星座的函数代码
2012/08/21 PHP
php无限级分类实现方法分析
2016/10/19 PHP
Laravel6.18.19如何优雅的切换发件账户
2020/06/14 PHP
jQuery 可以拖动的div实现代码 脚本之家修正版
2009/06/26 Javascript
ANT 压缩(去掉空格/注释)JS文件可提高js运行速度
2013/04/15 Javascript
javascript 手动给表增加数据的小例子
2013/07/10 Javascript
jquery下拉select控件操作方法分享(jquery操作select)
2014/03/25 Javascript
跟我学习javascript的基本类型和引用类型
2015/11/16 Javascript
JQuery validate插件Remote用法大全
2016/05/15 Javascript
AngularJS基础 ng-srcset 指令简单示例
2016/08/03 Javascript
Vue-router结合transition实现app前进后退动画切换效果的实例
2017/10/11 Javascript
vuex state及mapState的基础用法详解
2018/04/19 Javascript
使用layui实现的左侧菜单栏以及动态操作tab项方法
2019/09/10 Javascript
vue路由守卫,限制前端页面访问权限的例子
2019/11/11 Javascript
JavaScript实现切换多张图片
2021/01/27 Javascript
Python找出最小的K个数实例代码
2018/01/04 Python
celery4+django2定时任务的实现代码
2018/12/23 Python
详解Python数据可视化编程 - 词云生成并保存(jieba+WordCloud)
2019/03/26 Python
通过实例解析python描述符原理作用
2020/01/22 Python
python sorted函数原理解析及练习
2020/02/10 Python
python使用梯度下降和牛顿法寻找Rosenbrock函数最小值实例
2020/04/02 Python
Python是怎样处理json模块的
2020/07/16 Python
ghd官网:英国ghd直发器品牌
2018/05/04 全球购物
瑞典的玛丽小姐:Miss Mary of Sweden
2019/02/13 全球购物
澳大利亚购买健身器材网站:Gym Direct
2019/12/19 全球购物
linux面试题参考答案(9)
2016/01/29 面试题
企业爱心捐款倡议书
2015/04/27 职场文书
2015年外贸业务员工作总结范文
2015/05/23 职场文书
师范生教育见习总结
2015/06/23 职场文书
女性健康知识讲座主持词
2015/07/04 职场文书
《赵州桥》教学反思
2016/02/17 职场文书
2019生态环境保护倡议书!
2019/07/03 职场文书
详解Laravel制作API接口
2021/05/31 PHP