大家好!今天我帶來一個我認為很有趣的話題。我知道網路上有數十篇文章討論 TDD、BDD、測試設計模式、如何撰寫測試以及許多其他相關主題。然而,我很少看到文章解釋測試領域中更基本的術語——這些函數我們經常使用,但我們並不總是完全理解它們的含義或行為方式。如果您剛開始學習測試並且不確切了解函式庫函數的作用,那麼本文適合您。祝您閱讀愉快!
一旦開始編寫測試,您可能遇到的第一件事就是模擬。有時您已經使用過它們,但不知道它們的確切含義。那麼,讓我們開始吧。
模擬主要用於單元檢定。它們是用於模擬內容、物件或回應的工具,這些內容、物件或回應通常來自外部依賴項,或當您需要內容包含特定資訊時。
想像一下您正在測試一個電影推薦系統。該系統從 API 獲取電影列表並將其返回給您。
問題是:如果每次執行測試時都呼叫真正的 API,它可能會很慢且不一致(影片可能會有所不同,或者 API 可能會關閉),從而使測試不可靠。
好吧,Leo,我明白了問題,但是模擬如何解決這個問題? 嗯,這很簡單:您不呼叫 API,而是使用它的回應作為電影的靜態清單。它基本上是用該電影列表“偽造”API 響應。
在影片系統範例中,如果您想要測試一個名為 fetchMoviesFromAPI() 的函數,該函數使用 API 來取得影片,您可以建立一個模擬來模擬 API 回應,如下所示:
// This is the mock const MOVIES_FROM_API = [ { id: 1, name: "Interstellar" }, { id: 2, name: "Nosferatu" } ] // Here, we’re telling fetchMoviesFromAPI to return our mock instead of calling the real API. This is a stub, which you’ll learn about in the next section. const fetchMoviesFromAPI = jest.fn().mockResolvedValue(MOVIES_FROM_API) ;(async () => { { const expectedMovies = MOVIES_FROM_API const movies = await fetchMoviesFromAPI() expect(movies).toEqual(MOVIES_FROM_API) } })()
使用模擬,您的測試會變得更加高效,因為它們不依賴外部服務。此外,它們還獲得了可靠性,因為您可以完全控制返回結果,從而可以將重點放在驗證功能上,而不必擔心潛在的 API 不穩定或停機。
模擬是靜態對象,模擬來自測試所需的呼叫或其他對象的響應。
最終,這就像在不使用真正的汽油的情況下測試汽車一樣。您創建一個受控環境,以確保引擎在上路之前正常工作。
存根也是測試工具,但用途略有不同。他們用預先確定的東西替換函數的行為,通常使用模擬來傳回特定值。
存根取代了函數的行為。例如,當我訪問該電影 API 時,該函數不會進行真正的調用,而是會查看我們的模擬(電影的靜態列表)。
它們也提醒我們我們的測驗不應依賴外部服務或網際網路。
讓我給您一些背景資訊:假設您正在測試一個計算在線購買總價值的應用程式。此計算包括從外部服務獲取的費用。每次執行測試時,都需要進行此計算,這意味著需要呼叫外部服務。這可能會導致緩慢、不穩定、成本高昂(因為外部服務可能會按請求收費)和不一致的測試(值可能會改變)。
使用存根,您將用固定的預定義值(是的,模擬)替換真正的服務呼叫。您可以說:「始終傳回值 10 作為費用。」
,而不是呼叫費用服務。假設您想要測試函數calculateTotalPurchase(),該函數總結購物車商品的價值並添加運費。使用存根,您可以將運費服務替換為始終傳回「10」作為運費的值。像這樣:
// This is the mock const MOVIES_FROM_API = [ { id: 1, name: "Interstellar" }, { id: 2, name: "Nosferatu" } ] // Here, we’re telling fetchMoviesFromAPI to return our mock instead of calling the real API. This is a stub, which you’ll learn about in the next section. const fetchMoviesFromAPI = jest.fn().mockResolvedValue(MOVIES_FROM_API) ;(async () => { { const expectedMovies = MOVIES_FROM_API const movies = await fetchMoviesFromAPI() expect(movies).toEqual(MOVIES_FROM_API) } })()
這簡化了測試並確保其可重複性,這意味著它始終以相同的方式工作。此外,存根有助於隔離測試,無需擔心費用 API 的狀態或可用性。
總而言之,這就像使用量杯測試蛋糕配方,總是顯示 200 毫升牛奶,而不是測量實際的牛奶量。這樣,您只需測試是否可以混合原料,而不必擔心牛奶的測量是否正確。
我們探索了模擬(模擬物件)和存根(模擬函數行為)。現在,我們來談談間諜:他們到底是做什麼的?
Spies監控函數,記錄它們被呼叫了多少次,接收到了什麼參數,以及每次執行的結果。它們允許您觀察函數的行為而不改變它,確保一切按預期工作。
假設您正在測試專案的通知模組。每次訂單完成時,系統都應向客戶發送一條訊息並記錄一個條目。在這種情況下,您只想確保執行這些操作,但不想取代其中任何操作。使用間諜,您可以監視這些功能而不改變它們的行為。這可以讓您看到:
例如,如果您想使用間諜測試向客戶發送通知並記錄條目的completeOrder() 函數,您可以驗證:
// This is the mock const MOVIES_FROM_API = [ { id: 1, name: "Interstellar" }, { id: 2, name: "Nosferatu" } ] // Here, we’re telling fetchMoviesFromAPI to return our mock instead of calling the real API. This is a stub, which you’ll learn about in the next section. const fetchMoviesFromAPI = jest.fn().mockResolvedValue(MOVIES_FROM_API) ;(async () => { { const expectedMovies = MOVIES_FROM_API const movies = await fetchMoviesFromAPI() expect(movies).toEqual(MOVIES_FROM_API) } })()
總而言之,這就像放置一個相機來觀察廚師在廚房裡做什麼。你不干涉他們正在做的事情;你只需檢查他們是否正確遵循食譜即可。
所以,就是這樣!您已經學習並理解了術語“模擬”、“存根”和“間諜”,它們是創建可靠且高效的測試的基本元素。現在你可以繼續深化你的學習了。再見,再見!
以上是在 TDD 之前:為什麼需要知道 Mock、Stub 和 Spies 是什麼?的詳細內容。更多資訊請關注PHP中文網其他相關文章!