tornado.testing
— 異步程式碼單元測試支援¶
用於自動化測試的支援類別。
AsyncTestCase
和AsyncHTTPTestCase
:unittest.TestCase 的子類別,額外支援測試異步(基於IOLoop
)程式碼。ExpectLog
:讓測試日誌不那麼冗長。main()
:一個簡單的測試執行器(unittest.main() 的包裝器),支援 tornado.autoreload 模組,以便在程式碼變更時重新執行測試。
異步測試案例¶
- class tornado.testing.AsyncTestCase(methodName: str = 'runTest')[原始碼]¶
用於測試基於
IOLoop
的異步程式碼的TestCase
子類別。unittest 框架是同步的,因此測試必須在測試方法返回時完成。這表示異步程式碼無法像平常一樣使用,必須進行調整以適應。若要使用協程編寫測試,請使用
tornado.testing.gen_test
而不是tornado.gen.coroutine
來裝飾您的測試方法。此類別還提供了(已棄用的)
stop()
和wait()
方法,以用於更手動的測試風格。測試方法本身必須呼叫self.wait()
,而異步回呼應呼叫self.stop()
以表示完成。預設情況下,會為每個測試建構一個新的
IOLoop
,並以self.io_loop
提供。如果被測試的程式碼需要重複使用的全域IOLoop
,則子類別應覆寫get_new_ioloop
以傳回它,儘管從 Tornado 6.3 開始已棄用此做法。不應直接呼叫
IOLoop
的start
和stop
方法。請改用self.stop
和self.wait
。self.stop
傳遞的參數會從self.wait
傳回。可以在同一個測試中執行多個wait
/stop
週期。範例
# This test uses coroutine style. class MyTestCase(AsyncTestCase): @tornado.testing.gen_test def test_http_fetch(self): client = AsyncHTTPClient() response = yield client.fetch("https://tornado.dev.org.tw") # Test contents of response self.assertIn("FriendFeed", response.body) # This test uses argument passing between self.stop and self.wait. class MyTestCase2(AsyncTestCase): def test_http_fetch(self): client = AsyncHTTPClient() client.fetch("https://tornado.dev.org.tw/", self.stop) response = self.wait() # Test contents of response self.assertIn("FriendFeed", response.body)
- get_new_ioloop() IOLoop [原始碼]¶
傳回用於此測試的
IOLoop
。預設情況下,會為每個測試建立一個新的
IOLoop
。子類別可以覆寫此方法,以在每個測試中使用新的IOLoop
不適當的情況下(例如,如果存在使用預設IOLoop
的全域單例)或另一個系統(例如pytest-asyncio
)提供每個測試的事件迴圈時,傳回IOLoop.current()
。自 6.3 版起已棄用:此方法將在 Tornado 7.0 中移除。
- wait(condition: Optional[Callable[[...], bool]] = None, timeout: Optional[float] = None) Any [原始碼]¶
執行
IOLoop
,直到呼叫 stop 或逾時為止。如果發生逾時,將會拋出例外。預設逾時時間為 5 秒;可以使用
timeout
關鍵字引數覆寫,或者使用ASYNC_TEST_TIMEOUT
環境變數全域覆寫。如果
condition
不是None
,則在stop()
之後,將重新啟動IOLoop
,直到condition()
回傳True
。變更於 3.1 版本: 新增了
ASYNC_TEST_TIMEOUT
環境變數。
- class tornado.testing.AsyncHTTPTestCase(methodName: str = 'runTest')[原始碼]¶
一個啟動 HTTP 伺服器的測試案例。
子類別必須覆寫
get_app()
,它會回傳要測試的tornado.web.Application
(或其他HTTPServer
回呼)。測試通常會使用提供的self.http_client
來從此伺服器擷取 URL。範例,假設使用者指南中的「Hello, world」範例在
hello.py
中import hello class TestHelloApp(AsyncHTTPTestCase): def get_app(self): return hello.make_app() def test_homepage(self): response = self.fetch('/') self.assertEqual(response.code, 200) self.assertEqual(response.body, 'Hello, world')
對
self.fetch()
的呼叫等同於self.http_client.fetch(self.get_url('/'), self.stop) response = self.wait()
這說明了 AsyncTestCase 如何將異步操作(例如
http_client.fetch()
)轉換為同步操作。如果您需要在測試中執行其他異步操作,您可能需要自己使用stop()
和wait()
。- get_app() Application [原始碼]¶
應由子類別覆寫,以回傳
tornado.web.Application
或其他HTTPServer
回呼。
- fetch(path: str, raise_error: bool = False, **kwargs: Any) HTTPResponse [原始碼]¶
用於同步擷取 URL 的便利方法。
給定的路徑將會附加到本地伺服器的主機和埠。任何額外的關鍵字引數將會直接傳遞給
AsyncHTTPClient.fetch
(因此可以用來傳遞method="POST"
、body="..."
等)。如果路徑以 http:// 或 https:// 開頭,則會將其視為完整 URL 並按原樣擷取。
如果
raise_error
為True
,則當回應代碼不是 200 時,將會引發tornado.httpclient.HTTPError
。這與AsyncHTTPClient.fetch
的raise_error
引數行為相同,但此處的預設值為False
(在AsyncHTTPClient
中為True
),因為測試通常需要處理非 200 的回應代碼。變更於 5.0 版本: 新增對絕對 URL 的支援。
變更於 5.1 版本: 新增
raise_error
引數。自 5.1 版本起已棄用: 此方法目前會將任何例外狀況轉換為狀態代碼為 599 的
HTTPResponse
。在 Tornado 6.0 中,除了tornado.httpclient.HTTPError
之外的錯誤將會傳遞,而raise_error=False
將只會抑制因非 200 回應代碼而引發的錯誤。
- class tornado.testing.AsyncHTTPSTestCase(methodName: str = 'runTest')[原始碼]¶
一個會啟動 HTTPS 伺服器的測試案例。
介面大致上與
AsyncHTTPTestCase
相同。
- tornado.testing.gen_test(*, timeout: Optional[float] = None) Callable[[Callable[[...], Union[Generator, Coroutine]]], Callable[[...], None]] [原始碼]¶
- tornado.testing.gen_test(func: Callable[[...], Union[Generator, Coroutine]]) Callable[[...], None]
等同於
@gen.coroutine
的測試用途,適用於測試方法。因為
IOLoop
尚未執行,所以無法在測試中使用@gen.coroutine
。@gen_test
應適用於AsyncTestCase
子類別的測試方法。範例
class MyTest(AsyncHTTPTestCase): @gen_test def test_something(self): response = yield self.http_client.fetch(self.get_url('/'))
預設情況下,
@gen_test
會在 5 秒後逾時。可以使用ASYNC_TEST_TIMEOUT
環境變數全域覆寫逾時時間,或使用timeout
關鍵字參數針對每個測試覆寫。class MyTest(AsyncHTTPTestCase): @gen_test(timeout=10) def test_something_slow(self): response = yield self.http_client.fetch(self.get_url('/'))
請注意,
@gen_test
與AsyncTestCase.stop
、AsyncTestCase.wait
和AsyncHTTPTestCase.fetch
不相容。請改用如上所示的yield self.http_client.fetch(self.get_url())
。3.1 版本新增:
timeout
參數和ASYNC_TEST_TIMEOUT
環境變數。4.0 版本變更: 現在包裝器會傳遞
*args, **kwargs
,以便在具有引數的函式上使用。
控制日誌輸出¶
- class tornado.testing.ExpectLog(logger: Union[Logger, str], regex: str, required: bool = True, level: Optional[int] = None)[原始碼]¶
用於捕獲和抑制預期日誌輸出的上下文管理器。
在使錯誤條件測試不那麼嘈雜的同時,仍然保持意外的日誌條目可見很有用。*非執行緒安全。*
如果記錄任何例外堆疊追蹤,則會將屬性
logged_stack
設為True
。使用方式
with ExpectLog('tornado.application', "Uncaught exception"): error_response = self.fetch("/some_page")
4.3 版本變更: 新增了
logged_stack
屬性。建構 ExpectLog 上下文管理器。
- 參數
logger – 要監看的 Logger 物件(或記錄器的名稱)。傳遞空字串以監看根記錄器。
regex – 要比對的正規表示式。指定記錄器上任何與此正規表示式比對的日誌條目都會被抑制。
required – 如果為 true,如果在沒有比對任何日誌條目的情況下到達
with
陳述式結尾,則會引發例外。level – 來自
logging
模組的常數,指示預期的日誌等級。如果提供了這個參數,則只會考慮比對這個等級的日誌訊息。此外,如果需要(在ExpectLog
的持續時間內),提供的logger
會調整其等級以啟用預期的訊息。
6.1 版本變更: 新增了
level
參數。6.3 版本起已棄用: 在 Tornado 7.0 中,預設只會比對
WARNING
和更高的日誌等級。若要比對INFO
和更低的等級,必須使用level
引數。此變更旨在最小化tornado.testing.main
(預設啟用INFO
日誌) 與大多數其他測試執行器(包括 IDE 中的測試執行器,預設停用INFO
日誌)之間的差異。
測試執行器¶
- tornado.testing.main(**kwargs: Any) None [原始碼]¶
一個簡單的測試執行器。
這個測試執行器基本上等同於標準函式庫中的
unittest.main
,但增加了對 Tornado 風格的選項解析和日誌格式化的支援。使用AsyncTestCase
執行測試時,並非必須使用此main
函式;這些測試是獨立的,可以使用任何測試執行器執行。執行測試最簡單的方式是透過命令列
python -m tornado.testing tornado.test.web_test
請參考標準函式庫
unittest
模組,了解如何指定測試。具有許多測試的專案可能希望定義一個像
tornado/test/runtests.py
這樣的測試腳本。此腳本應定義一個返回測試套件的all()
方法,然後呼叫tornado.testing.main()
。請注意,即使使用測試腳本,命令列上指定單一測試時,all()
測試套件仍可被覆寫# Runs all tests python -m tornado.test.runtests # Runs one test python -m tornado.test.runtests tornado.test.web_test
額外的關鍵字參數會傳遞給
unittest.main()
。例如,使用tornado.testing.main(verbosity=2)
來顯示許多測試細節。完整的參數列表請參考 http://docs.python.org/library/unittest.html#unittest.main。變更於版本 5.0: 此函式不會產生自己的輸出;僅產生
unittest
模組產生的輸出(先前會添加 PASS 或 FAIL 日誌訊息)。