tornado.testing — 異步程式碼單元測試支援

用於自動化測試的支援類別。

  • AsyncTestCaseAsyncHTTPTestCase: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 開始已棄用此做法。

不應直接呼叫 IOLoopstartstop 方法。請改用 self.stopself.waitself.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 中移除。

stop(_arg: Optional[Any] = None, **kwargs: Any) None[原始碼]

停止 IOLoop,導致對 wait() 的一個擱置(或未來)呼叫傳回。

傳遞給 stop() 的關鍵字引數或單一位置引數會儲存,並由 wait() 傳回。

自 5.1 版起已棄用:stopwait 已棄用;請改用 @gen_test

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 環境變數。

自 5.1 版起已棄用:stopwait 已棄用;請改用 @gen_test

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_errorTrue,則當回應代碼不是 200 時,將會引發 tornado.httpclient.HTTPError。這與 AsyncHTTPClient.fetchraise_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 回應代碼而引發的錯誤。

get_httpserver_options() Dict[str, Any][原始碼]

子類別可能會覆寫此方法,以回傳伺服器的其他關鍵字引數。

get_http_port() int[原始碼]

回傳伺服器使用的埠。

每個測試都會選擇一個新的埠。

get_url(path: str) str[原始碼]

回傳測試伺服器上給定路徑的絕對 URL。

class tornado.testing.AsyncHTTPSTestCase(methodName: str = 'runTest')[原始碼]

一個會啟動 HTTPS 伺服器的測試案例。

介面大致上與 AsyncHTTPTestCase 相同。

get_ssl_options() Dict[str, Any][原始碼]

子類別可以覆寫此方法以選擇 SSL 選項。

預設包含一個自簽署的測試憑證。

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_testAsyncTestCase.stopAsyncTestCase.waitAsyncHTTPTestCase.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 日誌訊息)。

輔助函式

tornado.testing.bind_unused_port(reuse_port: bool = False, address: str = '127.0.0.1') Tuple[socket, int][原始碼]

將伺服器 socket 繫結到本機主機上可用的埠號。

返回一個 tuple (socket, port)。

變更於版本 4.4: 始終繫結到 127.0.0.1,而不解析名稱 localhost

變更於版本 6.2: 新增可選的 address 參數以覆寫預設的 “127.0.0.1”。

tornado.testing.get_async_test_timeout() float[原始碼]

取得非同步測試的全域逾時設定。

返回一個浮點數,以秒為單位的逾時時間。

新功能於版本 3.1。