單元測試可讓您在撰寫程式碼之後檢查品質,但也可以在開發期間使用單元測試來改進開發流程。您不需在開發完成後才撰寫測試,而可以在開發過程中即撰寫測試。這麼做可協助您設計可管理且可重複使用的小單元程式碼。測試程式碼也可以更輕鬆且快速徹底。
進行本機單元測試時,可在擁有的開發環境中執行測試,而不需遠端元件的輔助。App Engine 提供的測試公用程式採用了資料儲存庫及其他 App Engine 服務的本機實作。換句話說,您可以在本機執行程式碼的服務用途,無需透過服務虛設常式將程式碼部署至 App Engine。
服務虛設常式是一種模擬服務行為的方法。例如,撰寫 Datastore 與 Memcache 測試所示的資料儲存庫服務虛設常式可讓您測試資料儲存庫程式碼,而無須對真實的資料儲存庫提出任何要求。在資料儲存庫單元測試時儲存的實體不會儲存在資料儲存庫中,而是儲存在記憶體中,執行測試後即會遭到刪除。您可以執行快速的小型測試,而完全不需動用資料儲存庫。
本文件說明如何針對多種本機 App Engine 服務撰寫單元測試,並提供一些設定測試架構的相關資訊。
Python 2 測試公用程式簡介
名為 testbed
的 App Engine Python 模組可提供用於單元測試的服務虛設常式。
下列服務可使用服務虛設常式:
- 應用程式識別資訊
init_app_identity_stub
- Blobstore (使用
init_blobstore_stub
) - 功能 (使用
init_capability_stub
) - 資料儲存庫 (使用
init_datastore_v3_stub
) - 檔案 (使用
init_files_stub
) - 圖片 (僅供 dev_appserver 使用;使用
init_images_stub
) - LogService (使用
init_logservice_stub
) - 郵件 (使用
init_mail_stub
) - Memcache (使用
init_memcache_stub
) - 工作佇列 (使用
init_taskqueue_stub
) - 網址擷取 (使用
init_urlfetch_stub
) - 使用者服務 (使用
init_user_stub
)
如要同時初始化所有存根,您可以使用 init_all_stubs
。
編寫資料儲存庫和 Memcache 測試
本節會示範如何撰寫 datastore 和 Memcache 服務使用測試的程式碼。
請確認測試執行程式在 Python 載入路徑中具有適當的程式庫,包括 App Engine 程式庫、yaml
(包含在 App Engine SDK 中)、應用程式根目錄,以及應用程式程式碼預期的任何其他程式庫路徑修改項目 (例如本機 ./lib
目錄,如果有這類目錄的話)。例如:
import sys
sys.path.insert(1, 'google-cloud-sdk/platform/google_appengine')
sys.path.insert(1, 'google-cloud-sdk/platform/google_appengine/lib/yaml/lib')
sys.path.insert(1, 'myapp/lib')
匯入與測試服務相關的 Python unittest
模組和 App Engine 模組,在本例中為 memcache
和 ndb
,這兩者都會使用 Datastore 和 Memcache。也要匯入 testbed
模組。
接著建立 TestModel
類別。在本例中,會有函式檢查 Memcache 中是否儲存了實體。如果找不到實體,該函式就會在 Datastore 中檢查實體。在實際情況中,這可能會造成重複,因為 ndb
會在幕後使用 memcache,但在測試時,這仍是可行的模式。
接下來請建立測試案例。無論您測試哪些服務,測試案例都必須建立 Testbed
執行個體並啟用。測試案例也必須初始化相關服務存根,在本例中使用 init_datastore_v3_stub
和 init_memcache_stub
。如要瞭解如何初始化其他 App Engine 服務虛設常式,請參閱「Python 測試公用程式簡介」一文。
沒有引數的 init_datastore_v3_stub()
方法會使用一開始為空的記憶體內資料儲存庫。如果想要測試既有的資料儲存庫實體,請以引數形式將路徑名稱新增至 init_datastore_v3_stub()
。
除了 setUp()
之外,請納入可停用測試平台的 tearDown()
方法。這能還原原始服務虛設常式,避免不同測試彼此干擾。
然後實行測試。
現在,您可以使用 TestModel
撰寫使用資料儲存庫或 Memcache 服務虛設常式 (而非實際服務) 的測試。
例如,以下示範的方法會建立兩個實體:第一個實體的 number
屬性使用的是預設值 (42),而第二個實體的 number
屬性使用非預設值 (17)。該方法接著會建立 TestModel
實體的查詢,但僅適用預設值為 number
的實體。
擷取所有符合的實體後,方法會測試是否找到一個實體,以及該實體的 number
屬性值是否為預設值。
以下是另一個範例,這個方法會建立實體,並使用我們在前面建立的 GetEntityViaMemcache()
函式擷取實體。接著,該方法會測試是否已傳回實體,以及其 number
值是否與先前建立的實體相同。
最後,請叫用 unittest.main()
。
如果要執行測試,請參閱執行測試一文。
撰寫 Cloud Datastore 測試
如果應用程式使用的是 Cloud Datastore,建議您撰寫測試來驗證應用程式對於最終一致性的行為。db.testbed
提供了選項,讓撰寫相關測試變得十分容易:
PseudoRandomHRConsistencyPolicy
類別可讓您控管在每個全域 (非祖系) 查詢之前,寫入作業套用的可能性。將機率設定為 0% 時,代表我們指示資料儲存庫服務虛設常式儘可能提高最終一致性的程度來運作。採用最高程度的最終一致性表示即使寫入也一律無法套用,導致全域 (非祖系) 查詢永遠都無法找出變更。當然,這不代表您的應用程式在生產中執行時會面臨的最終一致性程度,但就測試目的而言,能夠每次都以這種方式設定本機資料儲存庫的行為相當實用。如果您使用非零機率,PseudoRandomHRConsistencyPolicy
會做出一連串確定的一致性決策,讓測試結果保持一致:
如要驗證您的應用程式在面對最終一致性的要求時是否正常運作,測試 API 非常實用。不過,請記住,本機的「高複製」讀取一致性模型只能說相當接近正式作業「高複製」的讀取一致性模型,而非完全相同。在本機環境中,如果執行的 get()
函式所屬 Entity
屬於的實體群組有未套用的寫入,未套用寫入的結果一律可見於後續全域查詢中。但在正式作業環境中就不是這樣。
撰寫郵件測試
您可以使用郵件服務虛設常式測試郵件服務。與其他測試平台支援的服務相同,首先需要將服務虛設常式初始化,然後叫用使用郵件 API 的程式碼,最後測試是否有傳送正確的訊息。
撰寫工作佇列測試
您可以使用工作佇列服務虛設常式撰寫使用 taskqueue 服務的測試。與其他測試平台支援的服務相同,首先需要將服務虛設常式初始化,然後叫用使用 taskqueue API 的程式碼,最後測試工作是否有正確加入佇列。
設定 queue.yaml
設定檔
如果您想針對與非預設佇列互動的程式碼執行測試,就必須建立並指定應用程式可用的 queue.yaml
檔案。以下是 queue.yaml
範例:
如需 queue.yaml 可用選項的詳細資訊,請參閱工作佇列設定。
初始化 Stub 時,會指定 queue.yaml
的位置:
self.testbed.init_taskqueue_stub(root_path='.')
在範例中,queue.yaml
與測試位於相同目錄。如果檔案位於其他資料夾,則需要在 root_path
中指定該路徑。
篩選工作
工作佇列輔助程式的 get_filtered_tasks
可讓您篩選排入佇列的工作。這樣一來,您就能更輕鬆地編寫需要驗證將多項工作排入佇列的程式碼的測試。
撰寫延期工作測試
如果您應用程式的程式碼使用延遲程式庫,您可以搭配 deferred
使用工作佇列虛設常式,驗證延遲函式是否已正確排入佇列及執行。
變更預設環境變數
App Engine 服務經常依賴環境變數。testbed.Testbed
類別的 activate()
方法會使用這些環境變數的預設值,但您可以依自己的測試需求設定自訂值,使用 testbed.Testbed
類別的 setup_env
方法。
舉例來說,假設您的測試將許多實體儲存在資料儲存庫之中,這些實體皆連結到相同的應用程式 ID。而現在您想要再次執行相同測試,但要使用不同的應用程式 ID,而非連結至已儲存實體的 ID。如要這麼做,請將新值以 app_id
的形式傳遞至 self.setup_env()
。
例如:
模擬登入
setup_env
的另一個常見用途是模擬使用者登入的情況 (不論是否具備管理員權限),以便檢查處理程序是否在每種情況下運作正常。
如今,您的測試方法可以呼叫 self.loginUser('', '')
模擬沒有使用者登入的情況、self.loginUser('[email protected]', '123')
模擬非管理員使用者登入的情況,以及 self.loginUser('[email protected]',
'123', is_admin=True)
模擬管理員使用者登入的情況。
設定測試架構
SDK 的測試公用程式並無特定要和任何架構搭配使用。您可以使用任何可用的 App Engine 測試執行程式來執行單元測試,例如 nose-gae 或 ferrisnose。您也可以自行撰寫簡單的測試執行程式,或使用以下測試執行程式。
下列指令碼使用 Python 的 unittest 模組。
您可以任意命名指令碼。執行時,請提供 Google Cloud CLI 或 Google App Engine SDK 安裝位置的路徑,以及測試模組的路徑。該指令碼會在所提供的路徑中找到所有測試,並將結果列印至標準錯誤訊息串之中。測試檔案會遵循慣例,在名稱前方加上前置字串 test
。
執行測試
只需透過 runner.py
指令碼,即可執行這些測試,詳情請參閱「設定測試架構」一節:
python runner.py <path-to-appengine-or-gcloud-SDK> .