doctest
--- 測(cè)試交互性的Python示例?
** 源代碼 ** Lib/doctest.py
doctest
模塊尋找像Python交互式代碼的文本,然后執(zhí)行這些代碼來(lái)確保它們的確就像展示的那樣正確運(yùn)行,有許多方法來(lái)使用doctest:
通過(guò)驗(yàn)證所有交互式示例仍然按照記錄的方式工作,以此來(lái)檢查模塊的文檔字符串是否是最新的。
通過(guò)驗(yàn)證來(lái)自一個(gè)測(cè)試文件或一個(gè)測(cè)試對(duì)象的交互式示例按預(yù)期工作,來(lái)進(jìn)行回歸測(cè)試。
為一個(gè)包寫(xiě)指導(dǎo)性的文檔,用輸入輸出的例子來(lái)說(shuō)明。 取決于是強(qiáng)調(diào)例子還是說(shuō)明性的文字,這有一種 "文本測(cè)試 "或 "可執(zhí)行文檔 "的風(fēng)格。
下面是一個(gè)小卻完整的示例模塊:
"""
This is the "example" module.
The example module supplies one function, factorial(). For example,
>>> factorial(5)
120
"""
def factorial(n):
"""Return the factorial of n, an exact integer >= 0.
>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
>>> factorial(30)
265252859812191058636308480000000
>>> factorial(-1)
Traceback (most recent call last):
...
ValueError: n must be >= 0
Factorials of floats are OK, but the float must be an exact integer:
>>> factorial(30.1)
Traceback (most recent call last):
...
ValueError: n must be exact integer
>>> factorial(30.0)
265252859812191058636308480000000
It must also not be ridiculously large:
>>> factorial(1e100)
Traceback (most recent call last):
...
OverflowError: n too large
"""
import math
if not n >= 0:
raise ValueError("n must be >= 0")
if math.floor(n) != n:
raise ValueError("n must be exact integer")
if n+1 == n: # catch a value like 1e300
raise OverflowError("n too large")
result = 1
factor = 2
while factor <= n:
result *= factor
factor += 1
return result
if __name__ == "__main__":
import doctest
doctest.testmod()
如果你直接在命令行里運(yùn)行 example.py
, doctest
將發(fā)揮它的作用。
$ python example.py
$
沒(méi)有輸出! 這很正常,這意味著所有的例子都成功了。 把 -v
傳給腳本,doctest
會(huì)打印出它所嘗試的詳細(xì)日志,并在最后打印出一個(gè)總結(jié)。
$ python example.py -v
Trying:
factorial(5)
Expecting:
120
ok
Trying:
[factorial(n) for n in range(6)]
Expecting:
[1, 1, 2, 6, 24, 120]
ok
以此類(lèi)推,最終以:
Trying:
factorial(1e100)
Expecting:
Traceback (most recent call last):
...
OverflowError: n too large
ok
2 items passed all tests:
1 tests in __main__
8 tests in __main__.factorial
9 tests in 2 items.
9 passed and 0 failed.
Test passed.
$
這就是對(duì)于高效地使用 doctest
你所需要知道的一切!開(kāi)始上手吧。 下面的章節(jié)提供了完整的細(xì)節(jié)。 請(qǐng)注意,在標(biāo)準(zhǔn)的 Python 測(cè)試套件和庫(kù)中有許多 doctest 的例子。特別有用的例子可以在標(biāo)準(zhǔn)測(cè)試文件 Lib/test/test_doctest.py
中找到。
簡(jiǎn)單用法:檢查Docstrings中的示例?
開(kāi)始使用doctest的最簡(jiǎn)單方法(但不一定是你將繼續(xù)這樣做的方式)是結(jié)束每個(gè)模塊 M
使用:
if __name__ == "__main__":
import doctest
doctest.testmod()
doctest
會(huì)隨后檢查模塊 M
中的文檔字符串。
以腳本形式運(yùn)行該模塊會(huì)使文檔中的例子得到執(zhí)行和驗(yàn)證:
python M.py
這不會(huì)顯示任何東西,除非一個(gè)例子失敗了,在這種情況下,失敗的例子和失敗的原因會(huì)被打印到stdout,最后一行的輸出是``***Test Failed*** N failures.``,其中*N*是失敗的例子的數(shù)量。
用``-v``來(lái)運(yùn)行它來(lái)切換,而不是:
python M.py -v
并將所有嘗試過(guò)的例子的詳細(xì)報(bào)告打印到標(biāo)準(zhǔn)輸出,最后還有各種總結(jié)。
你可以通過(guò)向 testmod()
傳遞 verbose=True
來(lái)強(qiáng)制執(zhí)行 verbose 模式,或者通過(guò)傳遞 verbose=False
來(lái)禁止它。 在這兩種情況下,sys.argv
都不會(huì)被 testmod()
檢查(所以傳遞 -v
或不傳遞都沒(méi)有影響)。
還有一個(gè)命令行快捷方式用于運(yùn)行 testmod()
。 你可以指示Python解釋器直接從標(biāo)準(zhǔn)庫(kù)中運(yùn)行doctest模塊,并在命令行中傳遞模塊名稱:
python -m doctest -v example.py
這將導(dǎo)入 example.py
作為一個(gè)獨(dú)立的模塊,并對(duì)其運(yùn)行 testmod()
。 注意,如果該文件是一個(gè)包的一部分,并且從該包中導(dǎo)入了其他子模塊,這可能無(wú)法正確工作。
簡(jiǎn)單的用法:檢查文本文件中的例子?
doctest 的另一個(gè)簡(jiǎn)單應(yīng)用是測(cè)試文本文件中的交互式例子。 這可以用 testfile()
函數(shù)來(lái)完成;:
import doctest
doctest.testfile("example.txt")
這個(gè)簡(jiǎn)短的腳本執(zhí)行并驗(yàn)證文件 example.txt
中包含的任何交互式 Python 示例。該文件的內(nèi)容被當(dāng)作一個(gè)巨大的文檔串來(lái)處理;該文件不需要包含一個(gè)Python程序!例如,也許 example.txt
包含以下內(nèi)容:
The ``example`` module
======================
Using ``factorial``
-------------------
This is an example text file in reStructuredText format. First import
``factorial`` from the ``example`` module:
>>> from example import factorial
Now use it:
>>> factorial(6)
120
運(yùn)行``doctest.testfile("example.txt")``,然后發(fā)現(xiàn)這個(gè)文檔中的錯(cuò)誤:
File "./example.txt", line 14, in example.txt
Failed example:
factorial(6)
Expected:
120
Got:
720
與 testmod()
一樣, testfile()
不會(huì)顯示任何東西,除非一個(gè)例子失敗。 如果一個(gè)例子失敗了,那么失敗的例子和失敗的原因?qū)⒈淮蛴〉絪tdout,使用的格式與 testmod()
相同。
默認(rèn)情況下,testfile()
在調(diào)用模塊的目錄中尋找文件。參見(jiàn)章節(jié) 基本API,了解可用于告訴它在其他位置尋找文件的可選參數(shù)的描述。
像 testmod()
一樣,testfile()
的詳細(xì)程度可以通過(guò)命令行 -v
切換或可選的關(guān)鍵字參數(shù) verbose 來(lái)設(shè)置。
還有一個(gè)命令行快捷方式用于運(yùn)行 testfile()
。 你可以指示Python解釋器直接從標(biāo)準(zhǔn)庫(kù)中運(yùn)行doctest模塊,并在命令行中傳遞文件名:
python -m doctest -v example.txt
因?yàn)槲募麤](méi)有以 .py
結(jié)尾,doctest
推斷它必須用 testfile()
運(yùn)行,而不是 testmod()
。
關(guān)于 testfile()
的更多信息,請(qǐng)參見(jiàn) 基本API 一節(jié)。
它是如何工作的?
這一節(jié)詳細(xì)研究了doctest的工作原理:它查看哪些文檔串,它如何找到交互式的用例,它使用什么執(zhí)行環(huán)境,它如何處理異常,以及如何用選項(xiàng)標(biāo)志來(lái)控制其行為。這是你寫(xiě)doctest例子所需要知道的信息;關(guān)于在這些例子上實(shí)際運(yùn)行doctest的信息,請(qǐng)看下面的章節(jié)。
哪些文件串被檢查了??
模塊的文檔串以及所有函數(shù)、類(lèi)和方法的文檔串都將被搜索。 導(dǎo)入模塊的對(duì)象不被搜索。
此外,如果 M.__test__
存在并且 "為真值",則它必須是一個(gè)字典,其中每個(gè)條目都將一個(gè)(字符串)名稱映射到一個(gè)函數(shù)對(duì)象、類(lèi)對(duì)象或字符串。 從 M.__test__
找到的函數(shù)和類(lèi)對(duì)象的文檔字符串會(huì)被搜索,而字符串會(huì)被當(dāng)作文檔字符串來(lái)處理。 在輸出時(shí),每個(gè)鍵 K
在 M.__test__
中都顯示為其名稱
<name of M>.__test__.K
任何發(fā)現(xiàn)的類(lèi)都會(huì)以類(lèi)似的方式進(jìn)行遞歸搜索,以測(cè)試其包含的方法和嵌套類(lèi)中的文檔串。
文檔串的例子是如何被識(shí)別的??
在大多數(shù)情況下,對(duì)交互式控制臺(tái)會(huì)話的復(fù)制和粘貼功能工作得很好,但是 doctest 并不試圖對(duì)任何特定的 Python shell 進(jìn)行精確的模擬。
>>> # comments are ignored
>>> x = 12
>>> x
12
>>> if x == 13:
... print("yes")
... else:
... print("no")
... print("NO")
... print("NO!!!")
...
no
NO
NO!!!
>>>
任何預(yù)期的輸出必須緊隨包含代碼的最后 '>>> '
或 '... '
行,預(yù)期的輸出(如果有的話)延伸到下一 '>>> '
行或全空白行。
fine輸出:
預(yù)期輸出不能包含一個(gè)全白的行,因?yàn)檫@樣的行被認(rèn)為是預(yù)期輸出的結(jié)束信號(hào)。 如果預(yù)期的輸出包含一個(gè)空行,在你的測(cè)試?yán)又?,在每一個(gè)預(yù)期有空行的地方加上``<BLANKLINE>``。
所有硬制表符都被擴(kuò)展為空格,使用 8 列的制表符。由測(cè)試代碼生成的輸出中的制表符不會(huì)被修改。 因?yàn)闃颖据敵鲋械娜魏斡仓票矸紩?huì)被擴(kuò)展,這意味著如果代碼輸出包括硬制表符,文檔測(cè)試通過(guò)的唯一方法是
NORMALIZE_WHITESPACE
選項(xiàng)或者 指令 是有效的。 另外,測(cè)試可以被重寫(xiě),以捕獲輸出并將其與預(yù)期值進(jìn)行比較,作為測(cè)試的一部分。這種對(duì)源碼中標(biāo)簽的處理是通過(guò)試錯(cuò)得出的,并被證明是最不容易出錯(cuò)的處理方式。通過(guò)編寫(xiě)一個(gè)自定義的DocTestParser
類(lèi),可以使用一個(gè)不同的算法來(lái)處理標(biāo)簽。向stdout的輸出被捕獲,但不向stderr輸出(異常回溯通過(guò)不同的方式被捕獲)。
如果你在交互式會(huì)話中通過(guò)反斜線續(xù)行,或出于任何其他原因使用反斜線,你應(yīng)該使用原始文件串,它將完全保留你輸入的反斜線:
>>> def f(x): ... r'''Backslashes in a raw docstring: m\n''' >>> print(f.__doc__) Backslashes in a raw docstring: m\n
否則,反斜杠將被解釋為字符串的一部分。例如,上面的``n``會(huì)被解釋為一個(gè)換行符。 另外,你可以在doctest版本中把每個(gè)反斜杠加倍(而不使用原始字符串):
>>> def f(x): ... '''Backslashes in a raw docstring: m\\n''' >>> print(f.__doc__) Backslashes in a raw docstring: m\n
起始列并不重要:
>>> assert "Easy!" >>> import math >>> math.floor(1.9) 1
并從預(yù)期的輸出中剝離出與開(kāi)始該例子的初始
'>>> '
行中出現(xiàn)的同樣多的前導(dǎo)空白字符。
什么是執(zhí)行上下文??
默認(rèn)情況下,每次 doctest
找到要測(cè)試的文檔串時(shí),它都會(huì)使用 M
的*淺層副本*,這樣運(yùn)行測(cè)試就不會(huì)改變模塊的真正全局變量,而且 M
的一個(gè)測(cè)試也不會(huì)留下臨時(shí)變量,從而意外地讓另一個(gè)測(cè)試通過(guò)。這意味著例子可以自由地使用 M
中的任何頂級(jí)定義的名字,以及正在運(yùn)行的文檔串中早期定義的名字。用例不能看到其他文檔串中定義的名字。
你可以通過(guò)將``globs=your_dict``傳遞給 testmod()
或 testfile()
來(lái)強(qiáng)制使用你自己的dict作為執(zhí)行環(huán)境。
異常如何處理??
沒(méi)問(wèn)題,只要回溯是這個(gè)例子產(chǎn)生的唯一輸出:只要粘貼回溯即可。1 由于回溯所包含的細(xì)節(jié)可能會(huì)迅速變化(例如,確切的文件路徑和行號(hào)),這是doctest努力使其接受的內(nèi)容具有靈活性的一種情況。
簡(jiǎn)單實(shí)例:
>>> [1, 2, 3].remove(42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: list.remove(x): x not in list
如果 ValueError
被觸發(fā),該測(cè)試就會(huì)成功,list.remove(x): x not in list
的細(xì)節(jié)如圖所示。
異常的預(yù)期輸出必須以回溯頭開(kāi)始,可以是以下兩行中的任何一行,縮進(jìn)程度與例子中的第一行相同:
Traceback (most recent call last):
Traceback (innermost last):
回溯頭的后面是一個(gè)可選的回溯堆棧,其內(nèi)容被doctest忽略。 回溯堆棧通常是省略的,或者從交互式會(huì)話中逐字復(fù)制的。
回溯堆棧的后面是最有用的部分:包含異常類(lèi)型和細(xì)節(jié)的一行(幾行)。 這通常是回溯的最后一行,但如果異常有多行細(xì)節(jié),則可以延伸到多行:
>>> raise ValueError('multi\n line\ndetail')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: multi
line
detail
最后三行(以 ValueError
開(kāi)頭)將與異常的類(lèi)型和細(xì)節(jié)進(jìn)行比較,其余的被忽略。
最佳實(shí)踐是省略回溯棧,除非它為這個(gè)例子增加了重要的文檔價(jià)值。 因此,最后一個(gè)例子可能更好,因?yàn)?
>>> raise ValueError('multi\n line\ndetail')
Traceback (most recent call last):
...
ValueError: multi
line
detail
請(qǐng)注意,回溯的處理方式非常特別。 特別是,在重寫(xiě)的例子中,...
的使用與 doctest 的 ELLIPSIS
選項(xiàng)無(wú)關(guān)。 該例子中的省略號(hào)可以不寫(xiě),也可以是三個(gè)(或三百個(gè))逗號(hào)或數(shù)字,或者是一個(gè)縮進(jìn)的 Monty Python 短劇的劇本。
有些細(xì)節(jié)你應(yīng)該讀一遍,但不需要記?。?/p>
Doctest 不能猜測(cè)你的預(yù)期輸出是來(lái)自異?;厮葸€是來(lái)自普通打印。 因此,例如,一個(gè)期望
ValueError: 42 is prime
的用例將通過(guò)測(cè)試,無(wú)論ValueError
是真的被觸發(fā),或者該用例只是打印了該回溯文本。 在實(shí)踐中,普通輸出很少以回溯標(biāo)題行開(kāi)始,所以這不會(huì)產(chǎn)生真正的問(wèn)題。回溯堆棧的每一行(如果有的話)必須比例子的第一行縮進(jìn), 或者 以一個(gè)非字母數(shù)字的字符開(kāi)始?;厮蓊^之后的第一行縮進(jìn)程度相同,并且以字母數(shù)字開(kāi)始,被認(rèn)為是異常細(xì)節(jié)的開(kāi)始。當(dāng)然,這對(duì)真正的回溯來(lái)說(shuō)是正確的事情。
當(dāng)
IGNORE_EXCEPTION_DETAIL
doctest 選項(xiàng)被指定時(shí),最左邊的冒號(hào)后面的所有內(nèi)容以及異常名稱中的任何模塊信息都被忽略。交互式 shell 省略了一些
SyntaxError
的回溯頭行。但 doctest 使用回溯頭行來(lái)區(qū)分異常和非異常。所以在罕見(jiàn)的情況下,如果你需要測(cè)試一個(gè)省略了回溯頭的SyntaxError
,你將需要手動(dòng)添加回溯頭行到你的測(cè)試用例中。
For some exceptions, Python displays the position of the error using
^
markers and tildes:>>> 1 + None File "<stdin>", line 1 1 + None ~~^~~~~~ TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
由于顯示錯(cuò)誤位置的行在異常類(lèi)型和細(xì)節(jié)之前,它們不被doctest檢查。 例如,下面的測(cè)試會(huì)通過(guò),盡管它把``^``標(biāo)記放在了錯(cuò)誤的位置:
>>> 1 + None File "<stdin>", line 1 1 + None ^~~~~~~~ TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
選項(xiàng)標(biāo)記?
一系列選項(xiàng)旗標(biāo)控制著 doctest 的各方面行為。 旗標(biāo)的符號(hào)名稱以模塊常量的形式提供,可以一起 bitwise ORed 并傳遞給各種函數(shù)。 這些名稱也可以在 doctest directives 中使用,并且可以通過(guò) -o
選項(xiàng)傳遞給 doctest 命令行接口。
3.4 新版功能: 命令行選項(xiàng) -o
。
第一組選項(xiàng)定義了測(cè)試語(yǔ)義,控制doctest如何決定實(shí)際輸出是否與用例的預(yù)期輸出相匹配方面的問(wèn)題。
- doctest.DONT_ACCEPT_TRUE_FOR_1?
默認(rèn)情況下,如果一個(gè)預(yù)期的輸出塊只包含
1
,那么實(shí)際的輸出塊只包含1
或只包含True
就被認(rèn)為是匹配的,同樣,0
與False
也是如此。 當(dāng)DONT_ACCEPT_TRUE_FOR_1
被指定時(shí),兩種替換都不允許。 默認(rèn)行為是為了適應(yīng) Python 將許多函數(shù)的返回類(lèi)型從整數(shù)改為布爾值;期望 "小整數(shù)" 輸出的測(cè)試在這些情況下仍然有效。 這個(gè)選項(xiàng)可能會(huì)消失,但不會(huì)在幾年內(nèi)消失。
- doctest.DONT_ACCEPT_BLANKLINE?
默認(rèn)情況下,如果一個(gè)預(yù)期輸出塊包含一個(gè)只包含字符串
<BLANKLINE>
的行,那么該行將與實(shí)際輸出中的一個(gè)空行相匹配。 因?yàn)橐粋€(gè)真正的空行是對(duì)預(yù)期輸出的限定,這是傳達(dá)預(yù)期空行的唯一方法。 當(dāng)DONT_ACCEPT_BLANKLINE
被指定時(shí),這種替換是不允許的。
- doctest.NORMALIZE_WHITESPACE?
當(dāng)指定時(shí),所有的空白序列(空白和換行)都被視為相等。預(yù)期輸出中的任何空白序列將與實(shí)際輸出中的任何空白序列匹配。默認(rèn)情況下,空白必須完全匹配。
NORMALIZE_WHITESPACE
在預(yù)期輸出非常長(zhǎng)的一行,而你想把它包在源代碼的多行中時(shí)特別有用。
- doctest.ELLIPSIS?
當(dāng)指定時(shí),預(yù)期輸出中的省略號(hào)(
...
)可以匹配實(shí)際輸出中的任何子串。這包括跨行的子串和空子串,所以最好保持簡(jiǎn)單的用法。復(fù)雜的用法會(huì)導(dǎo)致與``.*``在正則表達(dá)式中容易出現(xiàn)的 "oops, it matched too much!"相同的意外情況。
- doctest.IGNORE_EXCEPTION_DETAIL?
When specified, doctests expecting exceptions pass so long as an exception of the expected type is raised, even if the details (message and fully-qualified exception name) don't match.
For example, an example expecting
ValueError: 42
will pass if the actual exception raised isValueError: 3*14
, but will fail if, say, aTypeError
is raised instead. It will also ignore any fully-qualified name included before the exception class, which can vary between implementations and versions of Python and the code/libraries in use. Hence, all three of these variations will work with the flag specified:>>> raise Exception('message') Traceback (most recent call last): Exception: message >>> raise Exception('message') Traceback (most recent call last): builtins.Exception: message >>> raise Exception('message') Traceback (most recent call last): __main__.Exception: message
Note that
ELLIPSIS
can also be used to ignore the details of the exception message, but such a test may still fail based on whether the module name is present or matches exactly.在 3.2 版更改:
IGNORE_EXCEPTION_DETAIL
現(xiàn)在也忽略了與包含被測(cè)異常的模塊有關(guān)的任何信息。
- doctest.SKIP?
當(dāng)指定時(shí),完全不運(yùn)行這個(gè)用例。 這在doctest用例既是文檔又是測(cè)試案例的情況下很有用,一個(gè)例子應(yīng)該包括在文檔中,但不應(yīng)該被檢查。例如,這個(gè)例子的輸出可能是隨機(jī)的;或者這個(gè)例子可能依賴于測(cè)試驅(qū)動(dòng)程序所不能使用的資源。
SKIP標(biāo)志也可用于臨時(shí) "注釋" 用例。
- doctest.COMPARISON_FLAGS?
一個(gè)比特或運(yùn)算將上述所有的比較標(biāo)志放在一起。
第二組選項(xiàng)控制測(cè)試失敗的報(bào)告方式:
- doctest.REPORT_UDIFF?
當(dāng)指定時(shí),涉及多行預(yù)期和實(shí)際輸出的故障將使用統(tǒng)一的差異來(lái)顯示。
- doctest.REPORT_CDIFF?
當(dāng)指定時(shí),涉及多行預(yù)期和實(shí)際輸出的故障將使用上下文差異來(lái)顯示。
- doctest.REPORT_NDIFF?
當(dāng)指定時(shí),差異由``difflib.Differ``來(lái)計(jì)算,使用與流行的:file:ndiff.py`工具相同的算法。這是唯一一種標(biāo)記行內(nèi)和行間差異的方法。 例如,如果一行預(yù)期輸出包含數(shù)字``1`,而實(shí)際輸出包含字母``l``,那么就會(huì)插入一行,用圓點(diǎn)標(biāo)記不匹配的列位置。
- doctest.REPORT_ONLY_FIRST_FAILURE?
當(dāng)指定時(shí),在每個(gè) doctest 中顯示第一個(gè)失敗的用例,但隱藏所有其余用例的輸出。 這將防止 doctest 報(bào)告由于先前的失敗而中斷的正確用例;但也可能隱藏獨(dú)立于第一個(gè)失敗的不正確用例。 當(dāng)
REPORT_ONLY_FIRST_FAILURE
被指定時(shí),其余的用例仍然被運(yùn)行,并且仍然計(jì)入報(bào)告的失敗總數(shù);只是輸出被隱藏了。
- doctest.FAIL_FAST?
當(dāng)指定時(shí),在第一個(gè)失敗的用例后退出,不嘗試運(yùn)行其余的用例。因此,報(bào)告的失敗次數(shù)最多為1。這個(gè)標(biāo)志在調(diào)試時(shí)可能很有用,因?yàn)榈谝粋€(gè)失敗后的用例甚至不會(huì)產(chǎn)生調(diào)試輸出。
doctest命令行接受選項(xiàng)``-f``作為``-o FAIL_FAST``的簡(jiǎn)潔形式。
3.4 新版功能.
- doctest.REPORTING_FLAGS?
一個(gè)比特或操作將上述所有的報(bào)告標(biāo)志組合在一起。
還有一種方法可以注冊(cè)新的選項(xiàng)標(biāo)志名稱,不過(guò)這并不有用,除非你打算通過(guò)子類(lèi)來(lái)擴(kuò)展 doctest
內(nèi)部。
- doctest.register_optionflag(name)?
用給定的名稱創(chuàng)建一個(gè)新的選項(xiàng)標(biāo)志,并返回新標(biāo)志的整數(shù)值。
register_optionflag()
可以在繼承OutputChecker
或DocTestRunner
時(shí)使用,以創(chuàng)建子類(lèi)支持的新選項(xiàng)。register_optionflag()
應(yīng)始終使用以下方式調(diào)用:MY_FLAG = register_optionflag('MY_FLAG')
指令?
Doctest指令可以用來(lái)修改單個(gè)例子的 option flags 。 Doctest指令是在一個(gè)用例的源代碼后面的特殊Python注釋。
directive ::= "#" "doctest:"directive_options
directive_options ::=directive_option
(","directive_option
)\* directive_option ::=on_or_off
directive_option_name
on_or_off ::= "+" \| "-" directive_option_name ::= "DONT_ACCEPT_BLANKLINE" \| "NORMALIZE_WHITESPACE" \| ...
+
或 -
與指令選項(xiàng)名稱之間不允許有空格。 指令選項(xiàng)名稱可以是上面解釋的任何一個(gè)選項(xiàng)標(biāo)志名稱。
一個(gè)用例的 doctest 指令可以修改 doctest 對(duì)該用例的行為。 使用 +
來(lái)啟用指定的行為,或者使用 -
來(lái)禁用它。
For example, this test passes:
>>> print(list(range(20))) # doctest: +NORMALIZE_WHITESPACE
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
Without the directive it would fail, both because the actual output doesn't have two blanks before the single-digit list elements, and because the actual output is on a single line. This test also passes, and also requires a directive to do so:
>>> print(list(range(20))) # doctest: +ELLIPSIS
[0, 1, ..., 18, 19]
Multiple directives can be used on a single physical line, separated by commas:
>>> print(list(range(20))) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
[0, 1, ..., 18, 19]
If multiple directive comments are used for a single example, then they are combined:
>>> print(list(range(20))) # doctest: +ELLIPSIS
... # doctest: +NORMALIZE_WHITESPACE
[0, 1, ..., 18, 19]
As the previous example shows, you can add ...
lines to your example
containing only directives. This can be useful when an example is too long for
a directive to comfortably fit on the same line:
>>> print(list(range(5)) + list(range(10, 20)) + list(range(30, 40)))
... # doctest: +ELLIPSIS
[0, ..., 4, 10, ..., 19, 30, ..., 39]
請(qǐng)注意,由于所有的選項(xiàng)都是默認(rèn)禁用的,而指令只適用于它們出現(xiàn)的用例,所以啟用選項(xiàng) (通過(guò)指令中的 +
) 通常是唯一有意義的選擇。 然而,選項(xiàng)標(biāo)志也可以被傳遞給運(yùn)行測(cè)試的函數(shù),建立不同的默認(rèn)值。 在這種情況下,通過(guò)指令中的 -
來(lái)禁用一個(gè)選項(xiàng)可能是有用的。
警告?
doctest
是嚴(yán)格地要求在預(yù)期輸出中完全匹配。 如果哪怕只有一個(gè)字符不匹配,測(cè)試就會(huì)失敗。 這可能會(huì)讓你吃驚幾次,在你確切地了解到 Python 對(duì)輸出的保證和不保證之前。 例如,當(dāng)打印一個(gè)集合時(shí),Python 不保證元素以任何特定的順序被打印出來(lái),所以像:
>>> foo()
{"Hermione", "Harry"}
是不可靠的!一個(gè)變通方法是用:
>>> foo() == {"Hermione", "Harry"}
True
來(lái)取代。另一個(gè)是使用
>>> d = sorted(foo())
>>> d
['Harry', 'Hermione']
還有其他的問(wèn)題,但你會(huì)明白的。
Another bad idea is to print things that embed an object address, like
>>> id(1.0) # certain to fail some of the time
7948648
>>> class C: pass
>>> C() # the default repr() for instances embeds an address
<C object at 0x00AC18F0>
The ELLIPSIS
directive gives a nice approach for the last example:
>>> C() # doctest: +ELLIPSIS
<C object at 0x...>
浮點(diǎn)數(shù)在不同的平臺(tái)上也會(huì)有小的輸出變化,因?yàn)镻ython在浮點(diǎn)數(shù)的格式化上依賴于平臺(tái)的C庫(kù),而C庫(kù)在這個(gè)問(wèn)題上的質(zhì)量差異很大。:
>>> 1./7 # risky
0.14285714285714285
>>> print(1./7) # safer
0.142857142857
>>> print(round(1./7, 6)) # much safer
0.142857
形式``I/2.**J``的數(shù)字在所有的平臺(tái)上都是安全的,我經(jīng)常設(shè)計(jì)一些測(cè)試的用例來(lái)產(chǎn)生該形式的數(shù):
>>> 3./4 # utterly safe
0.75
簡(jiǎn)單的分?jǐn)?shù)也更容易讓人理解,這也使得文件更加完善。
基本API?
函數(shù) testmod()
和 testfile()
為 doctest 提供了一個(gè)簡(jiǎn)單的接口,應(yīng)該足以滿足大多數(shù)基本用途。關(guān)于這兩個(gè)函數(shù)的不太正式的介紹,請(qǐng)參見(jiàn) 簡(jiǎn)單用法:檢查Docstrings中的示例 和 簡(jiǎn)單的用法:檢查文本文件中的例子 部分。
- doctest.testfile(filename, module_relative=True, name=None, package=None, globs=None, verbose=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, parser=DocTestParser(), encoding=None)?
除了*filename*,所有的參數(shù)都是可選的,而且應(yīng)該以關(guān)鍵字的形式指定。
測(cè)試名為 filename 的文件中的用例。 返回``(failure_count, test_count)``。
可選參數(shù) module_relative 指定了文件名的解釋方式。
如果 module_relative 是
True
(默認(rèn)),那么 filename 指定一個(gè)獨(dú)立于操作系統(tǒng)的模塊相對(duì)路徑。 默認(rèn)情況下,這個(gè)路徑是相對(duì)于調(diào)用模塊的目錄的;但是如果指定了 package 參數(shù),那么它就是相對(duì)于該包的。 為了保證操作系統(tǒng)的獨(dú)立性, filename 應(yīng)該使用字符來(lái)分隔路徑段,并且不能是一個(gè)絕對(duì)路徑 (即不能以/
開(kāi)始)。如果 module_relative 是
False
,那么 filename 指定了一個(gè)操作系統(tǒng)特定的路徑。路徑可以是絕對(duì)的,也可以是相對(duì)的;相對(duì)路徑是相對(duì)于當(dāng)前工作目錄而言的。
可選參數(shù) name 給出了測(cè)試的名稱;默認(rèn)情況下,或者如果是``None``,那么使用``os.path.basename(filename)``。
可選參數(shù) package 是一個(gè) Python 包或一個(gè) Python 包的名字,其目錄應(yīng)被用作模塊相關(guān)文件名的基礎(chǔ)目錄。 如果沒(méi)有指定包,那么調(diào)用模塊的目錄將作為模塊相關(guān)文件名的基礎(chǔ)目錄。如果 module_relative 是``False``,那么指定 package 是錯(cuò)誤的。
可選參數(shù) globs 給出了一個(gè)在執(zhí)行示例時(shí)用作全局變量的dict。 這個(gè)dict的一個(gè)新的淺層副本將為doctest創(chuàng)建,因此它的用例將從一個(gè)干凈的地方開(kāi)始。默認(rèn)情況下,或者如果為``None``,使用一個(gè)新的空dict。
可選參數(shù) extraglobs 給出了一個(gè)合并到用于執(zhí)行用例全局變量中的dict。 這就像
dict.update()
一樣:如果 globs 和 extraglobs 有一個(gè)共同的鍵,那么 extraglobs 中的相關(guān)值會(huì)出現(xiàn)在合并的dict中。 默認(rèn)情況下,或者為``None`` ,則不使用額外的全局變量。這是一個(gè)高級(jí)功能,允許對(duì) doctest 進(jìn)行參數(shù)化。例如,可以為一個(gè)基類(lèi)寫(xiě)一個(gè)測(cè)試,使用該類(lèi)的通用名稱,然后通過(guò)傳遞一個(gè) extraglobs dict,將通用名稱映射到要測(cè)試的子類(lèi),從而重復(fù)用于測(cè)試任何數(shù)量的子類(lèi)。可選的參數(shù) verbose 如果為真值會(huì)打印很多東西,如果為假值則只打印失敗信息;默認(rèn)情況下,或者為
None
,只有當(dāng)'-v'
在sys.argv
中時(shí)才為真值。可選參數(shù) report 為T(mén)rue時(shí),在結(jié)尾處打印一個(gè)總結(jié),否則在結(jié)尾處什么都不打印。 在verbose模式下,總結(jié)是詳細(xì)的,否則總結(jié)是非常簡(jiǎn)短的(事實(shí)上,如果所有的測(cè)試都通過(guò)了,總結(jié)就是空的)。
可選參數(shù) optionflags (默認(rèn)值為0)是選項(xiàng)標(biāo)志的 bitwise OR 。參見(jiàn)章節(jié) 選項(xiàng)標(biāo)記 。
可選參數(shù) raise_on_error 默認(rèn)為False。 如果是True,在一個(gè)用例中第一次出現(xiàn)失敗或意外的異常時(shí),會(huì)觸發(fā)一個(gè)異常。這允許對(duì)失敗進(jìn)行事后調(diào)試。默認(rèn)行為是繼續(xù)運(yùn)行例子。
可選參數(shù) parser 指定一個(gè)
DocTestParser
(或子類(lèi)),它應(yīng)該被用來(lái)從文件中提取測(cè)試。它默認(rèn)為一個(gè)普通的解析器(即``DocTestParser()``)。可選參數(shù) encoding 指定了一個(gè)編碼,應(yīng)該用來(lái)將文件轉(zhuǎn)換為unicode。
- doctest.testmod(m=None, name=None, globs=None, verbose=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, exclude_empty=False)?
所有的參數(shù)都是可選的,除了 m 之外,都應(yīng)該以關(guān)鍵字的形式指定。
測(cè)試從模塊 m (或模塊
__main__
,如果 m 沒(méi)有被提供或?yàn)閌`None``)可達(dá)到的函數(shù)和類(lèi)的文檔串中的用例,從``m.__doc__``開(kāi)始。也測(cè)試從dict
m.__test__
可達(dá)到的用例,如果它存在并且不是None
。m.__test__
將名字(字符串)映射到函數(shù)、類(lèi)和字符串;函數(shù)和類(lèi)的文檔串被搜索到的用例;字符串被直接搜索到,就像它們是文檔串一樣。只搜索附屬于模塊 m 中的對(duì)象的文檔串。
返回
(failure_count, test_count)
。可選參數(shù) name 給出了模塊的名稱;默認(rèn)情況下,或者如果為
None
,則為m.__name__
。可選參數(shù) exclude_empty 默認(rèn)為假值。 如果為真值,沒(méi)有找到任何 doctest 的對(duì)象將被排除在考慮范圍之外。 默認(rèn)情況下是向后兼容,所以仍然使用
doctest.master.summarize()
和testmod()
的代碼會(huì)繼續(xù)得到?jīng)]有測(cè)試的對(duì)象的輸出。 較新的DocTestFinder
構(gòu)造器的 exclude_empty 參數(shù)默認(rèn)為真值。可選參數(shù) extraglobs 、 verbose 、 report 、 optionflags 、 raise_on_error 和 globs 與上述函數(shù)
testfile()
的參數(shù)相同,只是 globs 默認(rèn)為m.__dict__
。
- doctest.run_docstring_examples(f, globs, verbose=False, name='NoName', compileflags=None, optionflags=0)?
與對(duì)象 f 相關(guān)的測(cè)試用例;例如, f 可以是一個(gè)字符串、一個(gè)模塊、一個(gè)函數(shù)或一個(gè)類(lèi)對(duì)象。
dict 參數(shù) globs 的淺層拷貝被用于執(zhí)行環(huán)境。
可選參數(shù) name 在失敗信息中使用,默認(rèn)為
"NoName"
。如果可選參數(shù) verbose 為真,即使沒(méi)有失敗也會(huì)產(chǎn)生輸出。 默認(rèn)情況下,只有在用例失敗的情況下才會(huì)產(chǎn)生輸出。
可選參數(shù) compileflags 給出了Python編譯器在運(yùn)行例子時(shí)應(yīng)該使用的標(biāo)志集。默認(rèn)情況下,或者如果為
None
,標(biāo)志是根據(jù) globs 中發(fā)現(xiàn)的未來(lái)特征集推導(dǎo)出來(lái)的。可選參數(shù) optionflags 的作用與上述
testfile()
函數(shù)中的相同。
Unittest API?
doctest
提供了兩個(gè)函數(shù),可以用來(lái)從模塊和包含測(cè)試的文本文件中創(chuàng)建 unittest
測(cè)試套件。 要與 unittest
測(cè)試發(fā)現(xiàn)集成,請(qǐng)?jiān)谀愕臏y(cè)試模塊中包含一個(gè) load_tests()
函數(shù)::
import unittest
import doctest
import my_module_with_doctests
def load_tests(loader, tests, ignore):
tests.addTests(doctest.DocTestSuite(my_module_with_doctests))
return tests
有兩個(gè)主要函數(shù)用于從文本文件和帶doctest的模塊中創(chuàng)建 unittest.TestSuite
實(shí)例。
- doctest.DocFileSuite(*paths, module_relative=True, package=None, setUp=None, tearDown=None, globs=None, optionflags=0, parser=DocTestParser(), encoding=None)?
將一個(gè)或多個(gè)文本文件中的doctest測(cè)試轉(zhuǎn)換為一個(gè)
unittest.TestSuite
。返回的
unittest.TestSuite
將由 unittest 框架運(yùn)行,并運(yùn)行每個(gè)文件中的交互式示例。如果任何文件中的用例失敗了,那么合成的單元測(cè)試就會(huì)失敗,并觸發(fā)一個(gè)failureException
異常,顯示包含該測(cè)試的文件名和一個(gè)(有時(shí)是近似的)行號(hào)。傳遞一個(gè)或多個(gè)要檢查的文本文件的路徑(作為字符串)。
選項(xiàng)可以作為關(guān)鍵字參數(shù)提供:
可選參數(shù) module_relative 指定了 paths 中的文件名應(yīng)該如何解釋。
如果*module_relative*是
True
(默認(rèn)值),那么 paths 中的每個(gè)文件名都指定了一個(gè)獨(dú)立于操作系統(tǒng)的模塊相對(duì)路徑。 默認(rèn)情況下,這個(gè)路徑是相對(duì)于調(diào)用模塊的目錄的;但是如果指定了 package 參數(shù),那么它就是相對(duì)于該包的。 為了保證操作系統(tǒng)的獨(dú)立性,每個(gè)文件名都應(yīng)該使用字符來(lái)分隔路徑段,并且不能是絕對(duì)路徑(即不能以/
開(kāi)始)。如果 module_relative 是
False
,那么 paths 中的每個(gè)文件名都指定了一個(gè)操作系統(tǒng)特定的路徑。 路徑可以是絕對(duì)的,也可以是相對(duì)的;相對(duì)路徑是關(guān)于當(dāng)前工作目錄的解析。
可選參數(shù) package 是一個(gè)Python包或一個(gè)Python包的名字,其目錄應(yīng)該被用作 paths 中模塊相關(guān)文件名的基本目錄。 如果沒(méi)有指定包,那么調(diào)用模塊的目錄將作為模塊相關(guān)文件名的基礎(chǔ)目錄。 如果 module_relative 是
False
,那么指定 package 是錯(cuò)誤的。可選的參數(shù) setUp 為測(cè)試套件指定了一個(gè)設(shè)置函數(shù)。在運(yùn)行每個(gè)文件中的測(cè)試之前,它被調(diào)用。 setUp 函數(shù)將被傳遞給一個(gè)
DocTest
對(duì)象。 setUp函數(shù)可以通過(guò)測(cè)試的 globs 屬性訪問(wèn)測(cè)試的全局變量。可選的參數(shù) tearDown 指定了測(cè)試套件的卸載函數(shù)。 在運(yùn)行每個(gè)文件中的測(cè)試后,它會(huì)被調(diào)用。 tearDown 函數(shù)將被傳遞一個(gè)
DocTest
對(duì)象。 setUp函數(shù)可以通過(guò)測(cè)試的 globs 屬性訪問(wèn)測(cè)試的全局變量。可選參數(shù) globs 是一個(gè)包含測(cè)試的初始全局變量的字典。 這個(gè)字典的一個(gè)新副本為每個(gè)測(cè)試創(chuàng)建。 默認(rèn)情況下, globs 是一個(gè)新的空字典。
可選參數(shù) optionflags 為測(cè)試指定默認(rèn)的doctest選項(xiàng),通過(guò)將各個(gè)選項(xiàng)的標(biāo)志連接在一起創(chuàng)建。 參見(jiàn)章節(jié) 選項(xiàng)標(biāo)記 。參見(jiàn)下面的函數(shù)
set_unittest_reportflags()
,以了解設(shè)置報(bào)告選項(xiàng)的更好方法。可選參數(shù) parser 指定一個(gè)
DocTestParser
(或子類(lèi)),它應(yīng)該被用來(lái)從文件中提取測(cè)試。它默認(rèn)為一個(gè)普通的解析器(即``DocTestParser()``)。可選參數(shù) encoding 指定了一個(gè)編碼,應(yīng)該用來(lái)將文件轉(zhuǎn)換為unicode。
該全局
__file__
被添加到提供給用DocFileSuite()
從文本文件加載的doctest的全局變量中。
- doctest.DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None, setUp=None, tearDown=None, checker=None)?
將一個(gè)模塊的doctest測(cè)試轉(zhuǎn)換為
unittest.TestSuite
。返回的
unittest.TestSuite
將由 unittest 框架運(yùn)行,并運(yùn)行模塊中的每個(gè) doctest。 如果任何一個(gè)測(cè)試失敗,那么合成的單元測(cè)試就會(huì)失敗,并觸發(fā)一個(gè)failureException
異常,顯示包含該測(cè)試的文件名和一個(gè)(有時(shí)是近似的)行號(hào)。可選參數(shù) module 提供了要測(cè)試的模塊。 它可以是一個(gè)模塊對(duì)象或一個(gè)(可能是帶點(diǎn)的)模塊名稱。 如果沒(méi)有指定,則使用調(diào)用此函數(shù)的模塊。
可選參數(shù) globs 是一個(gè)包含測(cè)試的初始全局變量的字典。 這個(gè)字典的一個(gè)新副本為每個(gè)測(cè)試創(chuàng)建。 默認(rèn)情況下, globs 是一個(gè)新的空字典。
可選參數(shù) extraglobs 指定了一組額外的全局變量,這些變量被合并到 globs 中。 默認(rèn)情況下,不使用額外的全局變量。
可選參數(shù) test_finder 是
DocTestFinder
對(duì)象(或一個(gè)可替換的對(duì)象),用于從模塊中提取測(cè)試。可選參數(shù) setUp 、 tearDown 和 optionflags 與上述函數(shù)
DocFileSuite()
相同。這個(gè)函數(shù)使用與
testmod()
相同的搜索技術(shù)。在 3.5 版更改: 如果 module 不包含任何文件串,則
DocTestSuite()
返回一個(gè)空的unittest.TestSuite
,而不是觸發(fā)ValueError
。
DocTestSuite()
從 doctest.DocTestCase
實(shí)例中創(chuàng)建一個(gè) unittest.TestSuite
,而 DocTestCase
是 unittest.TestCase
的子類(lèi)。 DocTestCase
在這里沒(méi)有記錄(這是一個(gè)內(nèi)部細(xì)節(jié)),但研究其代碼可以回答關(guān)于 unittest
集成的實(shí)際細(xì)節(jié)問(wèn)題。
同樣, DocFileSuite()
從 doctest.DocFileCase
實(shí)例中創(chuàng)建一個(gè) unittest.TestSuite
,并且 DocFileCase
是 DocTestCase
的一個(gè)子類(lèi)。
所以這兩種創(chuàng)建 unittest.TestSuite
的方式都是運(yùn)行 DocTestCase
的實(shí)例。這一點(diǎn)很重要,因?yàn)橛幸粋€(gè)微妙的原因:當(dāng)你自己運(yùn)行 doctest
函數(shù)時(shí),你可以直接控制使用中的 doctest
選項(xiàng),通過(guò)傳遞選項(xiàng)標(biāo)志給 doctest
函數(shù)。 然而,如果你正在編寫(xiě)一個(gè) unittest
框架, unittest
最終會(huì)控制測(cè)試的運(yùn)行時(shí)間和方式。 框架作者通常希望控制 doctest
的報(bào)告選項(xiàng)(也許,例如,由命令行選項(xiàng)指定),但沒(méi)有辦法通過(guò) unittest
向 doctest
測(cè)試運(yùn)行者傳遞選項(xiàng)。
出于這個(gè)原因, doctest
也支持一個(gè)概念,即 doctest
報(bào)告特定于 unittest
支持的標(biāo)志,通過(guò)這個(gè)函數(shù):
- doctest.set_unittest_reportflags(flags)?
設(shè)置要使用的
doctest
報(bào)告標(biāo)志。參數(shù) flags 是選項(xiàng)標(biāo)志的 bitwise OR 。 參見(jiàn)章節(jié) 選項(xiàng)標(biāo)記 。 只有 "報(bào)告標(biāo)志" 可以被使用。
這是一個(gè)模塊的全局設(shè)置,并影響所有未來(lái)由模塊
unittest
運(yùn)行的測(cè)試:DocTestCase
的runTest()
方法會(huì)查看DocTestCase
實(shí)例構(gòu)建時(shí)為測(cè)試用例指定的選項(xiàng)標(biāo)志。 如果沒(méi)有指定報(bào)告標(biāo)志(這是典型的和預(yù)期的情況),doctest
的unittest
報(bào)告標(biāo)志被 bitwise ORed 到選項(xiàng)標(biāo)志中,這樣增加的選項(xiàng)標(biāo)志被傳遞給DocTestRunner
實(shí)例來(lái)運(yùn)行doctest。 如果在構(gòu)建DocTestCase
實(shí)例時(shí)指定了任何報(bào)告標(biāo)志,那么doctest
的unittest
報(bào)告標(biāo)志會(huì)被忽略。unittest
報(bào)告標(biāo)志的值在調(diào)用該函數(shù)之前是有效的,由該函數(shù)返回。
高級(jí) API?
基本 API 是一個(gè)簡(jiǎn)單的封裝,旨在使 doctest 易于使用。它相當(dāng)靈活,應(yīng)該能滿足大多數(shù)用戶的需求;但是,如果你需要對(duì)測(cè)試進(jìn)行更精細(xì)的控制,或者希望擴(kuò)展 doctest 的功能,那么你應(yīng)該使用高級(jí) API 。
高級(jí)API圍繞著兩個(gè)容器類(lèi),用于存儲(chǔ)從 doctest 案例中提取的交互式用例:
定義了額外的處理類(lèi)來(lái)尋找、解析和運(yùn)行,并檢查 doctest 的用例。
DocTestFinder
: 查找給定模塊中的所有文檔串,并使用DocTestParser
從每個(gè)包含交互式用例的文檔串中創(chuàng)建一個(gè)DocTest
。DocTestParser
: 從一個(gè)字符串(如一個(gè)對(duì)象的文檔串)創(chuàng)建一個(gè)DocTest
對(duì)象。DocTestRunner
: 執(zhí)行DocTest
中的用例,并使用OutputChecker
來(lái)驗(yàn)證其輸出。OutputChecker
: 將一個(gè)測(cè)試用例的實(shí)際輸出與預(yù)期輸出進(jìn)行比較,并決定它們是否匹配。
這些處理類(lèi)之間的關(guān)系總結(jié)在下圖中:
list of:
+------+ +---------+
|module| --DocTestFinder-> | DocTest | --DocTestRunner-> results
+------+ | ^ +---------+ | ^ (printed)
| | | Example | | |
v | | ... | v |
DocTestParser | Example | OutputChecker
+---------+
DocTest 對(duì)象?
- class doctest.DocTest(examples, globs, name, filename, lineno, docstring)?
應(yīng)該在單一命名空間中運(yùn)行的doctest用例的集合。構(gòu)造函數(shù)參數(shù)被用來(lái)初始化相同名稱的屬性。
DocTest
定義了以下屬性。 它們由構(gòu)造函數(shù)初始化,不應(yīng)該被直接修改。- globs?
例子應(yīng)該運(yùn)行的命名空間(又稱 globals )。這是一個(gè)將名字映射到數(shù)值的字典。例子對(duì)名字空間的任何改變(比如綁定新的變量)將在測(cè)試運(yùn)行后反映在
globs
中。
- lineno?
filename
中的行號(hào),這個(gè)DocTest
開(kāi)始的地方,或者行號(hào)不可用時(shí)為``None``。 這個(gè)行號(hào)相對(duì)于文件的開(kāi)頭來(lái)說(shuō)是零的。
- docstring?
從測(cè)試中提取的字符串,或者如果字符串不可用,或者為
None
,如果測(cè)試沒(méi)有從字符串中提取。
Example 對(duì)象?
- class doctest.Example(source, want, exc_msg=None, lineno=0, indent=0, options=None)?
單個(gè)交互式用例,由一個(gè) Python 語(yǔ)句及其預(yù)期輸出組成。 構(gòu)造函數(shù)參數(shù)被用來(lái)初始化相同名稱的屬性。
Example
定義了以下屬性。 它們由構(gòu)造函數(shù)初始化,不應(yīng)該被直接修改。- source?
一個(gè)包含該用例源碼的字符串。 源碼由一個(gè) Python 語(yǔ)句組成,并且總是以換行結(jié)束;構(gòu)造函數(shù)在必要時(shí)添加一個(gè)換行。
- want?
運(yùn)行這個(gè)用例的源碼的預(yù)期輸出(可以是 stdout ,也可以是異常情況下的回溯)。
want
以一個(gè)換行符結(jié)束,除非沒(méi)有預(yù)期的輸出,在這種情況下它是一個(gè)空字符串。 構(gòu)造函數(shù)在必要時(shí)添加一個(gè)換行。
- exc_msg?
用例產(chǎn)生的異常信息,如果這個(gè)例子被期望產(chǎn)生一個(gè)異常;或者為
None
,如果它不被期望產(chǎn)生一個(gè)異常。 這個(gè)異常信息與traceback.format_exception_only()
的返回值進(jìn)行比較。exc_msg
以換行結(jié)束,除非是None
。
- lineno?
包含本例的字符串中的行號(hào),即本例的開(kāi)始。 這個(gè)行號(hào)相對(duì)于包含字符串的開(kāi)頭來(lái)說(shuō)是以零開(kāi)始的。
- indent?
用例在包含字符串中的縮進(jìn),即在用例的第一個(gè)提示前有多少個(gè)空格字符。
- options?
一個(gè)從選項(xiàng)標(biāo)志到
True
或False
的字典映射,用于覆蓋這個(gè)例子的默認(rèn)選項(xiàng)。 任何不包含在這個(gè)字典中的選項(xiàng)標(biāo)志都被保留為默認(rèn)值(由DocTestRunner
的optionflags
指定)。默認(rèn)情況下,沒(méi)有選項(xiàng)被設(shè)置。
DocTestFinder 對(duì)象?
- class doctest.DocTestFinder(verbose=False, parser=DocTestParser(), recurse=True, exclude_empty=True)?
一個(gè)處理類(lèi),用于從一個(gè)給定的對(duì)象的 docstring 和其包含的對(duì)象的 docstring 中提取與之相關(guān)的
DocTest
。DocTest
可以從模塊、類(lèi)、函數(shù)、方法、靜態(tài)方法、類(lèi)方法和屬性中提取。可選的參數(shù) verbose 可以用來(lái)顯示查找器搜索到的對(duì)象。 它的默認(rèn)值是
False
(無(wú)輸出)。可選的參數(shù) parser 指定了
DocTestParser
對(duì)象(或一個(gè)可替換的對(duì)象),用于從文檔串中提取 doctest 。如果可選的參數(shù) recurse 是 False ,那么
DocTestFinder.find()
將只檢查給定的對(duì)象,而不是任何包含的對(duì)象。如果可選參數(shù) exclude_empty 為 False ,那么
DocTestFinder.find()
將包括對(duì)文檔字符串為空的對(duì)象的測(cè)試。DocTestFinder
定義了以下方法:- find(obj[, name][, module][, globs][, extraglobs])?
返回
DocTest
的列表,該列表由 obj 的文檔串或其包含的任何對(duì)象的文檔串定義。可選參數(shù) name 指定了對(duì)象的名稱;這個(gè)名稱將被用來(lái)為返回的
DocTest
構(gòu)建名稱。 如果沒(méi)有指定*name*,則使用obj.__name__
。可選參數(shù) module 是包含給定對(duì)象的模塊。如果沒(méi)有指定模塊或者是
None
,那么測(cè)試查找器將試圖自動(dòng)確定正確的模塊。 該對(duì)象被使用的模塊:作為一個(gè)默認(rèn)的命名空間,如果沒(méi)有指定 globs 。
為了防止 DocTestFinder 從其他模塊導(dǎo)入的對(duì)象中提取 DocTest 。 (包含有除 module 以外的模塊的對(duì)象會(huì)被忽略)。
找到包含該對(duì)象的文件名。
找到該對(duì)象在其文件中的行號(hào)。
如果 module 是
False
,將不會(huì)試圖找到這個(gè)模塊。 這是不明確的,主要用于測(cè)試 doctest 本身:如果 module 是False
,或者是None
但不能自動(dòng)找到,那么所有對(duì)象都被認(rèn)為屬于(不存在的)模塊,所以所有包含的對(duì)象將(遞歸地)被搜索到 doctest 。每個(gè)
DocTest
的 globals 是由 globs 和 extraglobs 組合而成的( extraglobs 的綁定覆蓋 globs 的綁定)。 為每個(gè)DocTest
創(chuàng)建一個(gè)新的 globals 字典的淺層拷貝。如果沒(méi)有指定 globs ,那么它默認(rèn)為模塊的 __dict__ ,如果指定了或者為{}
,則除外。 如果沒(méi)有指定 extraglobs ,那么它默認(rèn)為{}
。
DocTestParser 對(duì)象?
- class doctest.DocTestParser?
一個(gè)處理類(lèi),用于從一個(gè)字符串中提取交互式的用例,并使用它們來(lái)創(chuàng)建一個(gè)
DocTest
對(duì)象。DocTestParser
定義了以下方法:- get_doctest(string, globs, name, filename, lineno)?
從給定的字符串中提取所有的測(cè)試用例,并將它們收集到一個(gè)
DocTest
對(duì)象中。globs 、 name 、 filename 和 lineno 是新的
DocTest
對(duì)象的屬性。 更多信息請(qǐng)參見(jiàn)DocTest
的文檔。
DocTestRunner 對(duì)象?
- class doctest.DocTestRunner(checker=None, verbose=None, optionflags=0)?
一個(gè)處理類(lèi),用于執(zhí)行和驗(yàn)證
DocTest
中的交互式用例。預(yù)期輸出和實(shí)際輸出之間的比較是由一個(gè)
OutputChecker
完成的。 這種比較可以用一些選項(xiàng)標(biāo)志來(lái)定制;更多信息請(qǐng)看 選項(xiàng)標(biāo)記 部分。 如果選項(xiàng)標(biāo)志不夠,那么也可以通過(guò)向構(gòu)造函數(shù)傳遞OutputChecker
的子類(lèi)來(lái)定制比較。測(cè)試運(yùn)行器的顯示輸出可以通過(guò)兩種方式控制。首先,一個(gè)輸出函數(shù)可以被傳遞給
TestRunner.run()
;這個(gè)函數(shù)將被調(diào)用,并顯示出應(yīng)該顯示的字符串。 它的默認(rèn)值是sys.stdout.write
。 如果捕獲輸出是不夠的,那么也可以通過(guò)子類(lèi)化 DocTestRunner 來(lái)定制顯示輸出,并重寫(xiě)report_start()
,report_success()
,report_unexpected_exception()
和report_failure()
方法。可選的關(guān)鍵字參數(shù) checker 指定了
OutputChecker
對(duì)象(或其相似替換),它應(yīng)該被用來(lái)比較預(yù)期輸出和 doctest 用例的實(shí)際輸出。可選的關(guān)鍵字參數(shù) verbose 控制
DocTestRunner
的詳細(xì)程度。 如果 verbose 是True
,那么每個(gè)用例的信息都會(huì)被打印出來(lái),當(dāng)它正在運(yùn)行時(shí)。 如果 verbose 是False
,則只打印失敗的信息。 當(dāng) verbose 沒(méi)有指定,或者為None
,如果使用了命令行開(kāi)關(guān)-v
,則使用verbose輸出。可選的關(guān)鍵字參數(shù) optionflags 可以用來(lái)控制測(cè)試運(yùn)行器如何比較預(yù)期輸出和實(shí)際輸出,以及如何顯示失敗。更多信息,請(qǐng)參見(jiàn)章節(jié) 選項(xiàng)標(biāo)記 。
DocTestParser
定義了以下方法:- report_start(out, test, example)?
報(bào)告測(cè)試運(yùn)行器即將處理給定的用例。提供這個(gè)方法是為了讓
DocTestRunner
的子類(lèi)能夠定制他們的輸出;它不應(yīng)該被直接調(diào)用。example 是即將被處理的用。 test 是 包含用例 的測(cè)試。 out 是傳遞給
DocTestRunner.run()
的輸出函數(shù)。
- report_success(out, test, example, got)?
報(bào)告給定的用例運(yùn)行成功。 提供這個(gè)方法是為了讓
DocTestRunner
的子類(lèi)能夠定制他們的輸出;它不應(yīng)該被直接調(diào)用。example 是即將被處理的用例。 got 是這個(gè)例子的實(shí)際輸出。 test 是包含 example 的測(cè)試。 out 是傳遞給
DocTestRunner.run()
的輸出函數(shù)。
- report_failure(out, test, example, got)?
報(bào)告給定的用例運(yùn)行失敗。 提供這個(gè)方法是為了讓
DocTestRunner
的子類(lèi)能夠定制他們的輸出;它不應(yīng)該被直接調(diào)用。example 是即將被處理的用例。 got 是這個(gè)例子的實(shí)際輸出。 test 是包含 example 的測(cè)試。 out 是傳遞給
DocTestRunner.run()
的輸出函數(shù)。
- report_unexpected_exception(out, test, example, exc_info)?
報(bào)告給定的用例觸發(fā)了一個(gè)異常。 提供這個(gè)方法是為了讓
DocTestRunner
的子類(lèi)能夠定制他們的輸出;它不應(yīng)該被直接調(diào)用。example 是將要被處理的用例。 exc_info 是一個(gè)元組,包含關(guān)于異常的信息(如由
sys.exc_info()
返回)。 test 是包含 example 的測(cè)試。 out 是傳遞給DocTestRunner.run()
的輸出函數(shù)。
- run(test, compileflags=None, out=None, clear_globs=True)?
在 test (一個(gè)
DocTest
對(duì)象)中運(yùn)行這些用例,并使用寫(xiě)入函數(shù) out 顯示結(jié)果。這些用例都是在命名空間
test.globs
中運(yùn)行的。 如果 clear_globs 為 True (默認(rèn)),那么這個(gè)命名空間將在測(cè)試運(yùn)行后被清除,以幫助進(jìn)行垃圾回收。如果你想在測(cè)試完成后檢查命名空間,那么使用 clear_globs=False 。compileflags 給出了 Python 編譯器在運(yùn)行例子時(shí)應(yīng)該使用的標(biāo)志集。如果沒(méi)有指定,那么它將默認(rèn)為適用于 globs 的 future-import 標(biāo)志集。
每個(gè)用例的輸出都使用
DocTestRunner
的輸出檢查器進(jìn)行檢查,結(jié)果由DocTestRunner.report_*()
方法進(jìn)行格式化。
- summarize(verbose=None)?
打印這個(gè) DocTestRunner 運(yùn)行過(guò)的所有測(cè)試用例的摘要,并返回一個(gè) named tuple
TestResults(failed, attempted)
。可選的 verbose 參數(shù)控制摘要的詳細(xì)程度。 如果沒(méi)有指定 verbose ,那么將使用
DocTestRunner
的 verbose 。
OutputChecker 對(duì)象?
- class doctest.OutputChecker?
一個(gè)用于檢查測(cè)試用例的實(shí)際輸出是否與預(yù)期輸出相匹配的類(lèi)。
OutputChecker
定義了兩個(gè)方法:check_output()
,比較給定的一對(duì)輸出,如果它們匹配則返回True
;output_difference()
,返回一個(gè)描述兩個(gè)輸出之間差異的字符串。OutputChecker
定義了以下方法:- check_output(want, got, optionflags)?
如果一個(gè)用例的實(shí)際輸出( got )與預(yù)期輸出( want )匹配,則返回
True
。 如果這些字符串是相同的,總是被認(rèn)為是匹配的;但是根據(jù)測(cè)試運(yùn)行器使用的選項(xiàng)標(biāo)志,也可能有幾種非精確的匹配類(lèi)型。 參見(jiàn)章節(jié) 選項(xiàng)標(biāo)記 了解更多關(guān)于選項(xiàng)標(biāo)志的信息。
- output_difference(example, got, optionflags)?
返回一個(gè)字符串,描述給定用例( example )的預(yù)期輸出和實(shí)際輸出( got )之間的差異。 optionflags 是用于比較 want 和 got 的選項(xiàng)標(biāo)志集。
調(diào)試?
Doctest 提供了幾種調(diào)試 doctest 用例的機(jī)制:
有幾個(gè)函數(shù)將測(cè)試轉(zhuǎn)換為可執(zhí)行的 Python 程序,這些程序可以在 Python 調(diào)試器,
pdb
下運(yùn)行。DebugRunner
類(lèi)是DocTestRunner
的一個(gè)子類(lèi),它為第一個(gè)失敗的用例觸發(fā)一個(gè)異常,包含關(guān)于這個(gè)用例的信息。這些信息可以用來(lái)對(duì)這個(gè)用例進(jìn)行事后調(diào)試。由
DocTestSuite()
生成的unittest
用例支持由unittest.TestCase
定義的debug()
方法,。你可以在 doctest 的用例中加入對(duì)
pdb.set_trace()
的調(diào)用,當(dāng)這一行被執(zhí)行時(shí),你會(huì)進(jìn)入 Python 調(diào)試器。 然后你可以檢查變量的當(dāng)前值,等等。 例如,假設(shè)a.py
只包含這個(gè)模塊 docstring""" >>> def f(x): ... g(x*2) >>> def g(x): ... print(x+3) ... import pdb; pdb.set_trace() >>> f(3) 9 """
那么一個(gè)交互式Python會(huì)話可能是這樣的:
>>> import a, doctest >>> doctest.testmod(a) --Return-- > <doctest a[1]>(3)g()->None -> import pdb; pdb.set_trace() (Pdb) list 1 def g(x): 2 print(x+3) 3 -> import pdb; pdb.set_trace() [EOF] (Pdb) p x 6 (Pdb) step --Return-- > <doctest a[0]>(2)f()->None -> g(x*2) (Pdb) list 1 def f(x): 2 -> g(x*2) [EOF] (Pdb) p x 3 (Pdb) step --Return-- > <doctest a[2]>(1)?()->None -> f(3) (Pdb) cont (0, 3) >>>
將測(cè)試轉(zhuǎn)換為 Python 代碼的函數(shù),并可能在調(diào)試器下運(yùn)行合成的代碼:
- doctest.script_from_examples(s)?
將帶有用例的文本轉(zhuǎn)換為腳本。
參數(shù) s 是一個(gè)包含測(cè)試用例的字符串。 該字符串被轉(zhuǎn)換為 Python 腳本,其中 s 中的 doctest 用例被轉(zhuǎn)換為常規(guī)代碼,其他的都被轉(zhuǎn)換為 Python 注釋。 生成的腳本將以字符串的形式返回。例如,
import doctest print(doctest.script_from_examples(r""" Set x and y to 1 and 2. >>> x, y = 1, 2 Print their sum: >>> print(x+y) 3 """))
顯示:
# Set x and y to 1 and 2. x, y = 1, 2 # # Print their sum: print(x+y) # Expected: ## 3
這個(gè)函數(shù)在內(nèi)部被其他函數(shù)使用(見(jiàn)下文),但當(dāng)你想把一個(gè)交互式 Python 會(huì)話轉(zhuǎn)化為 Python 腳本時(shí),也會(huì)很有用。
- doctest.testsource(module, name)?
將一個(gè)對(duì)象的 doctest 轉(zhuǎn)換為一個(gè)腳本。
參數(shù) module 是一個(gè)模塊對(duì)象,或者一個(gè)模塊帶點(diǎn)的名稱,包含對(duì)其 doctest 感興趣的對(duì)象。 參數(shù) name 是具有感興趣的測(cè)試的對(duì)象的名稱(在模塊中)。 結(jié)果是一個(gè)字符串,包含該對(duì)象的文本串轉(zhuǎn)換為 Python 腳本,如上面
script_from_examples()
所述。 例如,如果模塊a.py
包含一個(gè)頂級(jí)函數(shù)f()
,那么import a, doctest print(doctest.testsource(a, "a.f"))
打印函數(shù)
f()
的文檔串的腳本版本,將測(cè)試轉(zhuǎn)換為代碼,其余部分放在注釋中。
- doctest.debug(module, name, pm=False)?
對(duì)一個(gè)對(duì)象的 doctest 進(jìn)行調(diào)試。
module 和 name 參數(shù)與上面函數(shù)
testsource()
的參數(shù)相同。 被命名對(duì)象的文本串的合成 Python 腳本被寫(xiě)入一個(gè)臨時(shí)文件,然后該文件在 Python 調(diào)試器pdb
的控制下運(yùn)行。module.__dict__
的一個(gè)淺層拷貝被用于本地和全局的執(zhí)行環(huán)境。可選參數(shù) pm 控制是否使用事后調(diào)試。 如果 pm 為 True ,則直接運(yùn)行腳本文件,只有當(dāng)腳本通過(guò)引發(fā)一個(gè)未處理的異常而終止時(shí),調(diào)試器才會(huì)介入。如果是這樣,就會(huì)通過(guò)
pdb.post_mortem()
調(diào)用事后調(diào)試,并傳遞未處理異常的跟蹤對(duì)象。如果沒(méi)有指定 pm ,或者是 False ,腳本將從一開(kāi)始就在調(diào)試器下運(yùn)行,通過(guò)傳遞一個(gè)適當(dāng)?shù)?exec()
調(diào)用給pdb.run()
。
- doctest.debug_src(src, pm=False, globs=None)?
在一個(gè)字符串中調(diào)試 doctest 。
這就像上面的函數(shù)
debug()
,只是通過(guò) src 參數(shù),直接指定一個(gè)包含測(cè)試用例的字符串。可選參數(shù) pm 的含義與上述函數(shù)
debug()
的含義相同。可選的參數(shù) globs 給出了一個(gè)字典,作為本地和全局的執(zhí)行環(huán)境。 如果沒(méi)有指定,或者為
None
,則使用一個(gè)空的字典。如果指定,則使用字典的淺層拷貝。
DebugRunner
類(lèi),以及它可能觸發(fā)的特殊異常,是測(cè)試框架作者最感興趣的,在此僅作簡(jiǎn)要介紹。請(qǐng)看源代碼,特別是 DebugRunner
的文檔串(這是一個(gè)測(cè)試?。┮粤私飧嗉?xì)節(jié)。
- class doctest.DebugRunner(checker=None, verbose=None, optionflags=0)?
DocTestRunner
的一個(gè)子類(lèi),一旦遇到失敗,就會(huì)觸發(fā)一個(gè)異常。 如果一個(gè)意外的異常發(fā)生,就會(huì)引發(fā)一個(gè)UnexpectedException
異常,包含測(cè)試、用例和原始異常。 如果輸出不匹配,那么就會(huì)引發(fā)一個(gè)DocTestFailure
異常,包含測(cè)試、用例和實(shí)際輸出。關(guān)于構(gòu)造函數(shù)參數(shù)和方法的信息,請(qǐng)參見(jiàn)
DocTestRunner
部分的文檔 高級(jí) API 。
DebugRunner
實(shí)例可能會(huì)觸發(fā)兩種異常。
- exception doctest.DocTestFailure(test, example, got)?
DocTestRunner
觸發(fā)的異常,表示一個(gè) doctest 用例的實(shí)際輸出與預(yù)期輸出不一致。構(gòu)造函數(shù)參數(shù)被用來(lái)初始化相同名稱的屬性。
DocTestFailure
定義了以下屬性:
- DocTestFailure.got?
用例的實(shí)際輸出。
- exception doctest.UnexpectedException(test, example, exc_info)?
一個(gè)由
DocTestRunner
觸發(fā)的異常,以提示一個(gè) doctest 用例引發(fā)了一個(gè)意外的異常。 構(gòu)造函數(shù)參數(shù)被用來(lái)初始化相同名稱的屬性。
UnexpectedException
定義了以下屬性:
- UnexpectedException.exc_info?
一個(gè)包含意外異常信息的元組,由
sys.ex_info()
返回。
肥皂盒?
正如介紹中提到的, doctest
已經(jīng)發(fā)展到有三個(gè)主要用途:
檢查 docstring 中的用例。
回歸測(cè)試。
可執(zhí)行的文檔/文字測(cè)試。
這些用途有不同的要求,區(qū)分它們是很重要的。特別是,用晦澀難懂的測(cè)試用例來(lái)填充你的文檔字符串會(huì)使文檔變得很糟糕。
在編寫(xiě)文檔串時(shí),要謹(jǐn)慎地選擇文檔串的用例。這是一門(mén)需要學(xué)習(xí)的藝術(shù)——一開(kāi)始可能并不自然。用例應(yīng)該為文檔增加真正的價(jià)值。 一個(gè)好的用例往往可以抵得上許多文字。如果用心去做,這些用例對(duì)你的用戶來(lái)說(shuō)是非常有價(jià)值的,而且隨著時(shí)間的推移和事情的變化,收集這些用例所花費(fèi)的時(shí)間也會(huì)得到很多倍的回報(bào)。 我仍然驚訝于我的 doctest
用例在一個(gè)“無(wú)害”的變化后停止工作。
Doctest 也是回歸測(cè)試的一個(gè)很好的工具,特別是如果你不吝嗇解釋的文字。 通過(guò)交錯(cuò)的文本和用例,可以更容易地跟蹤真正的測(cè)試,以及為什么。當(dāng)測(cè)試失敗時(shí),好的文本可以使你更容易弄清問(wèn)題所在,以及如何解決。 的確,你可以在基于代碼的測(cè)試中寫(xiě)大量的注釋,但很少有程序員這樣做。許多人發(fā)現(xiàn),使用 doctest 方法反而能使測(cè)試更加清晰。 也許這只是因?yàn)?doctest 使寫(xiě)散文比寫(xiě)代碼容易一些,而在代碼中寫(xiě)注釋則有點(diǎn)困難。 我認(rèn)為它比這更深入:當(dāng)寫(xiě)一個(gè)基于 doctest 的測(cè)試時(shí),自然的態(tài)度是你想解釋你的軟件的細(xì)微之處,并用例子來(lái)說(shuō)明它們。這反過(guò)來(lái)又自然地導(dǎo)致了測(cè)試文件從最簡(jiǎn)單的功能開(kāi)始,然后邏輯地發(fā)展到復(fù)雜和邊緣案例。 一個(gè)連貫的敘述是結(jié)果,而不是一個(gè)孤立的函數(shù)集合,似乎是隨機(jī)的測(cè)試孤立的功能位。 這是一種不同的態(tài)度,產(chǎn)生不同的結(jié)果,模糊了測(cè)試和解釋之間的區(qū)別。
回歸測(cè)試最好限制在專用對(duì)象或文件中。 有幾種組織測(cè)試的選擇:
編寫(xiě)包含測(cè)試案例的文本文件作為交互式例子,并使用
testfile()
或DocFileSuite()
來(lái)測(cè)試這些文件。 建議這樣做,盡管對(duì)于新的項(xiàng)目來(lái)說(shuō)是最容易做到的,從一開(kāi)始就設(shè)計(jì)成使用 doctest 。定義命名為
_regrtest_topic
的函數(shù),由單個(gè)文檔串組成,包含命名主題的測(cè)試用例。 這些函數(shù)可以包含在與模塊相同的文件中,或分離出來(lái)成為一個(gè)單獨(dú)的測(cè)試文件。定義一個(gè)從回歸測(cè)試主題到包含測(cè)試用例的文檔串的
__test__
字典映射。
當(dāng)你把你的測(cè)試放在一個(gè)模塊中時(shí),這個(gè)模塊本身就可以成為測(cè)試運(yùn)行器。 當(dāng)一個(gè)測(cè)試失敗時(shí),你可以安排你的測(cè)試運(yùn)行器只重新運(yùn)行失敗的測(cè)試,同時(shí)調(diào)試問(wèn)題。 下面是這樣一個(gè)測(cè)試運(yùn)行器的最小例子:
if __name__ == '__main__':
import doctest
flags = doctest.REPORT_NDIFF|doctest.FAIL_FAST
if len(sys.argv) > 1:
name = sys.argv[1]
if name in globals():
obj = globals()[name]
else:
obj = __test__[name]
doctest.run_docstring_examples(obj, globals(), name=name,
optionflags=flags)
else:
fail, total = doctest.testmod(optionflags=flags)
print("{} failures out of {} tests".format(fail, total))
備注
- 1
不支持同時(shí)包含預(yù)期輸出和異常的用例。試圖猜測(cè)一個(gè)在哪里結(jié)束,另一個(gè)在哪里開(kāi)始,太容易出錯(cuò)了,而且這也會(huì)使測(cè)試變得混亂。