在咱們探索Twisted的過程當中寫了不少代碼,但目前咱們卻忽略了一些重要的東西 —— 測試.你也是會懷疑怎樣用像 unittest 這樣Python自帶的同步框架測試異步代碼.答案是你不能.正如咱們已經發現的,同步代碼和異步代碼是不能混合的,至少不容易.html
幸運地是,Twisted包含本身的測試框架,叫 trial,它支持測試異步代碼(固然你也能夠用它測試同步代碼).python
咱們假設你已經熟悉了 unittest 的機理和類似的測試框架,它容許你經過定義類建立測試.這個類一般是一個父類(一般叫"TestCase")的子類,類中的方法以"test"開頭並被視做一個測試.框架負責發現全部的測試,一個接一個地運行它們,並伴有可選項 setUp
和 tearDown
步驟,以後報告結果.react
例子
git
你能夠在 tests/test_poetry.py 中找到一些關於測試的例子.爲了確保咱們全部的例子是自包含的(以便你不用擔憂PYTHONPAYH設置),咱們將全部須要的代碼拷貝到測試模塊中.固然正常狀況,你只需導入須要測試的模塊.github
這個例子既測試詩歌客戶端又測試服務器,經過使用客戶端從測試服務器抓取一首詩. 爲了提供一個可供測試的詩歌服務器, 咱們在測試案例中實現 setUp 方法:web
class PoetryTestCase(TestCase): def setUp(self): factory = PoetryServerFactory(TEST_POEM) from twisted.internet import reactor self.port = reactor.listenTCP(0, factory, interface="127.0.0.1") self.portnum = self.port.getHost().port
這個 setUp 方法用一首測試詩創建詩歌服務器,而後監聽一個隨機開放端口.咱們保存了端口號,以便實際測試須要時能夠利用.固然測試結束時咱們會用 tearDown 清除測試服務器:服務器
def tearDown(self): port, self.port = self.port, None return port.stopListening()
這把咱們帶到了第一個測試, test_client, 用 get_poetry 從測試服務器獲取詩歌而且驗證這就是咱們所指望的詩歌:框架
def test_client(self): """The correct poem is returned by get_poetry.""" d = get_poetry('127.0.0.1', self.portnum) def got_poem(poem): self.assertEquals(poem, TEST_POEM) d.addCallback(got_poem) return d
注意咱們的測試函數返回一個 deferred
.在 trial
中,每一個測試方法都以回調的方式運行.這意味着 reactor
正在運行而且咱們能夠以測試的一部分執行異步操做.咱們僅僅須要讓框架知道測試是異步的,這能夠經過採用常規的Twisted方式 —— 返回deferred
來實現.異步
trial
框架在調用 tearDown
方法以前將等待直到 deferred
激發,而且當 deferred
失敗時將使測試失敗(如,最後一個回調/錯誤回調對失敗).若是咱們的 deferred
反應太慢(默認2分鐘)它一樣會使測試失敗.這意味着若是測試完成,咱們知道 deferred
激發了,所以咱們的回調激發了而且運行了 assertEquals
測試方法.函數
咱們的第二個測試, test_failure, 證明 get_poetry 以適當的方式失敗了,若是不能鏈接到服務器:
def test_failure(self): """The correct failure is returned by get_poetry when connecting to a port with no server.""" d = get_poetry('127.0.0.1', -1) return self.assertFailure(d, ConnectionRefusedError)
這裏咱們打算鏈接到一個無效端口,以後使用trial提供的 assertFailure
方法.這個方法相似於熟悉的 assertRaises
方法可是是針對異步代碼的.它返回一個 deferred
,若是給定的 deferred
失敗則返回成功,不然返回失敗.
你能夠用trial腳本本身運行這些測試,以下:
trial tests/test_poetry.py
你將看到顯示每一個測試案例的輸出,OK表示測試經過了.
因爲當談到基本API時,trial與unittest十分類似,因此開始寫測試十分容易.若是你的測試使用異步代碼,僅僅返回 deferred
就能夠了,trial將負責其他的事情.你也能夠從 setUp
或 tearDown
方法返回一個 deferred
,若是它們也須要異步.
任何來自測試的日誌消息將被收集到當前文件夾下的一個文件中,即"_trial_temp", trial會自動建立它. 除了打印到屏幕的錯誤,日誌是調試失敗測試的實用入口.
圖33顯示了一個正在進行中的假想測試:
圖33: 進行中的trial測試
若是你以前使用過相似的框架,這是一個熟悉的模型,除了全部測試相關的方法可能返回 deferreds
.
trial框架是一個關於如何"異步運做"的很好例子,包括級聯在整個程序中的變化.爲了使一個測試(或任何函數,方法)是異步的,它必須:
非阻塞而且,一般
返回一個 deferred
.
但這意味着不管什麼調用,那個函數必須願意接收一個 deferred
,而且非阻塞(如此又好像返回了一個 deferred
).如此這般一層又一層.這樣就呼喚出現trial同樣的框架,能夠處理返回 deferreds
的異步測試.
總結
這就是關於單元測試的內容.若是你想了解更多關於如何爲Twisted代碼寫單元測試的例子,你只須要看看Twisted代碼自己.Twisted框架自帶了一套很是龐大的單元測試,並且每一個新的發佈又會加入不少.因爲這些測試在被接受入代碼庫以前,通過嚴格的代碼評論以及Twisted專家們的仔細審查,故而它們是告訴你如何以正確方式測試Twisted代碼的極好例子.
在 :doc:`p16` 中,咱們將使用Twisted工具將詩歌服務器轉化爲一個真正的守護進程.