Python單元測(cè)試:assertTrue是真值,assertFalse是假值
在這篇文章中,我們將介紹單元測(cè)試的布爾斷言方法 assertTrue 和 assertFalse 與身份斷言 assertIs 之間的區(qū)別。
定義
下面是目前單元測(cè)試模塊文檔中關(guān)于 assertTrue 和 assertFalse 的說(shuō)明,代碼進(jìn)行了高亮:
assertTrue(expr, msg=None) assertFalse(expr, msg=None) |
|
|
Mozilla 開(kāi)發(fā)者網(wǎng)絡(luò)中定義 真值 如下:
在一個(gè)布爾值的上下文環(huán)境中能變成“真”的值在 Python 中等價(jià)于:
- bool(expr) is True
這個(gè)和 assertTrue 的測(cè)試目的完全匹配。
因此該文檔中已經(jīng)指出 assertTrue 返回真值,assertFalse 返回假值。這些斷言方法從接受到的值構(gòu)造出一個(gè)布爾值,然后判斷它。同樣文檔中也建議我們根本不應(yīng)該使用 assertTrue 和 assertFalse。
在實(shí)踐中怎么理解?
我們使用一個(gè)非常簡(jiǎn)單的例子 - 一個(gè)名稱為 always_true 的函數(shù),它返回 True。我們?yōu)樗鼘?xiě)一些測(cè)試用例,然后改變代碼,看看測(cè)試用例的表現(xiàn)。
作為開(kāi)始,我們先寫(xiě)兩個(gè)測(cè)試用例。一個(gè)是“寬松的”:使用 assertTrue 來(lái)測(cè)試真值。另外一個(gè)是“嚴(yán)格的”:使用文檔中建議的 assertIs 函數(shù)。
- import unittest
- from func import always_true
- class TestAlwaysTrue(unittest.TestCase):
- def test_assertTrue(self):
- """
- always_true returns a truthy value
- """
- result = always_true()
- self.assertTrue(result)
- def test_assertIs(self):
- """
- always_true returns True
- """
- result = always_true()
- self.assertIs(result, True)
下面是 func.py 中的非常簡(jiǎn)單的函數(shù)代碼:
- def always_true():
- """
- I'm always True.
- Returns:
- bool: True
- """
- return True
當(dāng)你運(yùn)行時(shí),所有測(cè)試都通過(guò)了:
- always_true returns True ... ok
- always_true returns a truthy value ... ok
- ----------------------------------------------------------------------
- Ran 2 tests in 0.004s
- OK
開(kāi)心ing~
現(xiàn)在,某個(gè)人將 always_true 函數(shù)改變成下面這樣:
- def always_true():
- """
- I'm always True.
- Returns:
- bool: True
- """
- return 'True'
它現(xiàn)在是用返回字符串 "True" 來(lái)替代之前反饋的 True (布爾值)。(當(dāng)然,那個(gè)“某人”并沒(méi)有更新文檔 - 后面我們會(huì)增加難度。)
這次結(jié)果并不如開(kāi)心了:
- always_true returns True ... FAIL
- always_true returns a truthy value ... ok
- ======================================================================
- FAIL: always_true returns True
- ----------------------------------------------------------------------
- Traceback (most recent call last):
- File "/tmp/assertttt/test.py", line 22, in test_is_true
- self.assertIs(result, True)
- AssertionError: 'True' is not True
- ----------------------------------------------------------------------
- Ran 2 tests in 0.004s
- FAILED (failures=1)
只有一個(gè)測(cè)試用例失敗了!這意味著 assertTrue 給了我們一個(gè)誤判false-positive。在它不應(yīng)該通過(guò)測(cè)試時(shí),它通過(guò)了。很幸運(yùn)的是我們第二個(gè)測(cè)試是使用 assertIs 來(lái)寫(xiě)的。
因此,跟手冊(cè)上了解到的信息一樣,為了保證 always_true 的功能和更嚴(yán)格測(cè)試的結(jié)果保持一致,應(yīng)該使用assertIs 而不是 assertTrue。
使用斷言的輔助方法
使用 assertIs 來(lái)測(cè)試返回 True 和 False 來(lái)冗長(zhǎng)了。因此,如果你有個(gè)項(xiàng)目需要經(jīng)常檢查是否是返回了True 或者 False,那們你可以自己編寫(xiě)一些斷言的輔助方法。
這好像并沒(méi)有節(jié)省大量的代碼,但是我個(gè)人覺(jué)得提高了代碼的可讀性。
- def assertIsTrue(self, value):
- self.assertIs(value, True)
- def assertIsFalse(self, value):
- self.assertIs(value, False)
總結(jié)
一般來(lái)說(shuō),我的建議是讓測(cè)試越嚴(yán)格越好。如果你想測(cè)試 True 或者 False,聽(tīng)從文檔的建議,使用assertIs。除非不得已,否則不要使用 assertTrue 和 assertFalse。
如果你面對(duì)的是一個(gè)可以返回多種類型的函數(shù),例如,有時(shí)候返回布爾值,有時(shí)候返回整形,那么考慮重構(gòu)它。這是代碼的異味。在 Python 中,拋出一個(gè)異常比使用 False 表示錯(cuò)誤更好。
此外,如果你確實(shí)想使用斷言來(lái)判斷函數(shù)的返回值是否是真,可能還存在第二個(gè)代碼異味 - 代碼是正確封裝了嗎?如果 assertTrue 和 assertFalse 是根據(jù)正確的 if 語(yǔ)句來(lái)執(zhí)行,那么值得檢查下你是否把所有你想要的東西都封裝在合適的位置。也許這些 if 語(yǔ)句應(yīng)該封裝在測(cè)試的函數(shù)中。
測(cè)試開(kāi)心!