掃二維碼與項目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
Lightbot在這篇文章中,我們將介紹單元測試的布爾斷言方法 assertTrue 和 assertFalse 與身份斷言 assertIs 之間的區(qū)別。

創(chuàng)新互聯(lián)專業(yè)提供成都主機托管四川主機托管成都服務(wù)器托管四川服務(wù)器托管,支持按月付款!我們的承諾:貴族品質(zhì)、平民價格,機房位于中國電信/網(wǎng)通/移動機房,成都服務(wù)器托管服務(wù)有保障!
下面是目前單元測試模塊文檔中關(guān)于assertTrue 和 assertFalse 的說明,代碼進行了高亮:
assertTrue(expr, msg=None)
assertFalse(expr, msg=None)
測試該表達式是真值(或假值)。 注:這等價于”bool(expr) is True”而不等價于”expr is True”(后一種情況請使用 assertIs(expr, True))。 Mozilla 開發(fā)者網(wǎng)絡(luò)中定義 真值 如下: 在一個布爾值的上下文環(huán)境中能變成“真”的值 在 Python 中等價于:
bool(expr) is True
這個和 assertTrue 的測試目的完全匹配。
因此該文檔中已經(jīng)指出 assertTrue 返回真值,assertFalse 返回假值。這些斷言方法從接受到的值構(gòu)造出一個布爾值,然后判斷它。同樣文檔中也建議我們根本不應(yīng)該使用 assertTrue 和 assertFalse。
我們使用一個非常簡單的例子 – 一個名稱為 always_true的函數(shù),它返回 True。我們?yōu)樗鼘懸恍y試用例,然后改變代碼,看看測試用例的表現(xiàn)。
作為開始,我們先寫兩個測試用例。一個是“寬松的”:使用 assertTrue來測試真值。另外一個是“嚴格的”:使用文檔中建議的 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中的非常簡單的函數(shù)代碼:
def always_true():
""" I'm always True. Returns: bool: True """
return True
當你運行時,所有測試都通過了:
always_true returns True ... ok
always_true returns a truthy value ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.004s
OK
開心ing~
現(xiàn)在,某個人將 “always_true” 函數(shù)改變成下面這樣:
def always_true():
""" I'm always True. Returns: bool: True """
return 'True'
它現(xiàn)在是用返回字符串”True” 來替代之前反饋的 True (布爾值)。(當然,那個“某人”并沒有更新文檔 – 后面我們會增加難度。)
這次結(jié)果并不如開心了:
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)
只有一個測試用例失敗了!這意味著 assertTrue 給了我們一個誤判false-positive。在它不應(yīng)該通過測試時,它通過了。很幸運的是我們第二個測試是使用 assertIs 來寫的。
因此,跟手冊上了解到的信息一樣,為了保證 always_true 的功能和更嚴格測試的結(jié)果保持一致,應(yīng)該使用 assertIs 而不是 assertTrue。
使用 assertIs 來測試返回 True 和 False 來冗長了。因此,如果你有個項目需要經(jīng)常檢查是否是返回了 True 或者 False,那們你可以自己編寫一些斷言的輔助方法。
這好像并沒有節(jié)省大量的代碼,但是我個人覺得提高了代碼的可讀性。
def assertIsTrue(self, value):
self.assertIs(value, True)
def assertIsFalse(self, value):
self.assertIs(value, False)
一般來說,我的建議是讓測試越嚴格越好。如果你想測試 True 或者 False,聽從文檔的建議,使用 assertIs。除非不得已,否則不要使用 assertTrue 和 assertFalse。
如果你面對的是一個可以返回多種類型的函數(shù),例如,有時候返回布爾值,有時候返回整形,那么考慮重構(gòu)它。這是代碼的異味。在 Python 中,拋出一個異常比使用 False 表示錯誤更好。
此外,如果你確實想使用斷言來判斷函數(shù)的返回值是否是真,可能還存在第二個代碼異味 – 代碼是正確封裝了嗎?如果 assertTrue 和 assertFalse 是根據(jù)正確的 if 語句來執(zhí)行,那么值得檢查下你是否把所有你想要的東西都封裝在合適的位置。也許這些 if語句應(yīng)該封裝在測試的函數(shù)中。
測試開心!

我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流