Python中的斷言用起來很是簡單,你能夠在assert
後面跟上任意判斷條件,若是斷言失敗則會拋出異常。html
>>> 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
還不如不寫,寫了我就想罵娘。直接拋一個異常來得更痛快一些。python
一個稍微改進一丟丟的方案就是把必要的信息也放到assert
語句後面,好比這樣。git
>>> 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.'
看上去還行吧,可是其實寫的很蛋疼。假如你是一名測試汪,有成千上萬的測試案例須要作斷言作驗證,相信你面對以上作法,心中必定有千萬只那種馬奔騰而過。github
無論你是你是搞測試仍是開發的,想必聽過很多測試框架。你猜到我要說什麼了吧?對,不用測試框架裏的斷言機制,你是否是灑。shell
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 =========================== """"
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,感謝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>. """
不只僅是你和我對Python中的斷言表示不知足,因此你們都爭相發明本身的assert包。在這裏我強烈推薦assertpy 這個包,它異常強大並且好評如潮。spa
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')
從它的github 主頁 文檔上你會發現它支持了幾乎你能想到的全部測試場景,包括但不限於如下列表。
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技術愛好者,目前從事測試開發相關工做,轉載請註明原文出處。
歡迎關注個人博客 https://betacat.online,你能夠到個人公衆號中去當吃瓜羣衆。