WHAT--定義
Mock測試就是在測試過程當中,對於某些不容易構造或者不容易獲取的對象,用一個虛擬的對象來建立以便測試的測試方法(來自百度百科)。通俗點講,就是:作個假對象、響應來實現某種特定場景的測試。java
WHY--使用緣由
(1)底層數據複雜,依賴嚴重等狀況,按照真實的場景去使用,耗時、成本較大等;
(2)依賴的底層單元還沒有開發完成,或現有資源難以知足當前模塊的測試需求;
(3)一些特定的異常場景,較難復現等;mysql
WHEN & WHERE--使用場景
--其實WHY裏面,已經回答了這個問題。如下兩條也是使用原則,沒必要每一個單元測試都使用Mock。
(1)單元測試/接口測試中測試對象依賴其餘對象,這些對象的構造複雜、耗時或者根本沒法構
造(未交付);
----簡單的場景,不必使用,可能會耗時更多。異常場景、複雜場景、影響工做效率場景等建議使用。
(2)咱們只測試對象內部邏輯的質量,不關心依賴對象的邏輯正確性和穩定性;
----即:底層的代碼已確保由底層保障,不須要調用方關心。sql
Dummy Object,測試代碼須要Dummy Object是由於有了它才能經過編譯,測試才能跑起來,但其實測試中可能根本就用不到它。數據庫
eg1:函數
例如,建立BlogService 須要 BlogDao,但你可能測試BlogService 的一個方法,它根本就沒用到BlogDao。此時,你能夠用 new BlogService(new NullBlogDao()), NullBlogDao 就是Dummy Object,由於它的存在只是爲了經過編譯,它根本就不參與測試。單元測試
eg2:
測試
圖中main函數,須要統計對象個數。須要實例PersonImpl的對象,然而PersonImpl是Person接口的實現類,因此必須實現Person接口的抽象方法study(),因此此時PersonImpl類中的實現方法在main函數中並無起到任何做用,可是必須寫上,確保程序不報錯,這時候study()就能夠理解爲一個Dummy。spa
Stub 參與測試, 但你不在意它是什麼時候何地以何種方式參與測試的,它的存在是爲了讓測試跑起來,在測試過程當中產生的調用提供預備好的應答,一般不該答計劃以外的任何事,很是常見的狀況是你須要它提供一些返回值。例如,你能夠用HttpContextStub 來代替真正的HttpContext, 用它提供例如SessionId, ResquestParameter 之類的值。你的測試可能會用到這些值,但你不會去驗證是否是getSessionId() 被調用了,更不會去驗證它是什麼時候何地以何種方式被調用的。code
如圖中,跳過查mysql的數據操做,模擬測試樁來代替查數據庫的步驟,不須要關心查mysql的操做,只關注數據按照這個格式返回。對象
spy 能夠理解爲偵查,它負責彙報狀況,持續追蹤什麼方法被調用了,以及調用過程當中傳遞了哪些參數。你能用它來實現測試斷言,好比一個特定的方法是否被調用或者是否使用正確的參數調用。當你須要測試兩個對象間的某些協議或者關係時會很是有用。
public void testRemoveFlightLogging_recordingTestStub() throws Exception { // Fixture setup FlightDto expectedFlightDto = createAnUnregFlight(); FlightManagementFacade facade = new FlightManagementFacadeImpl(); // Test Double setup AuditLogSpy logSpy = new AuditLogSpy(); facade.setAuditLog(logSpy); // Exercise facade.removeFlight(expectedFlightDto.getFlightNumber()); // Verify state assertFalse("flight still exists after being removed", facade.flightExists( expectedFlightDto. getFlightNumber())); // Verify indirect outputs using retrieval interface of spy assertEquals("number of calls", 1, logSpy.getNumberOfCalls()); assertEquals("action code", Helper.REMOVE_FLIGHT_ACTION_CODE, logSpy.getActionCode()); assertEquals("date", helper.getTodaysDateWithoutTime(), logSpy.getDate()); assertEquals("user", Helper.TEST_USER_NAME, logSpy.getUser()); assertEquals("detail", expectedFlightDto.getFlightNumber(), logSpy.getDetail()); }
fake 是一個具有完整功能實現和行爲的對象,行爲上來講它和這個類型的真實對象上同樣,但不一樣於它所模擬的類,它使測試變得更加容易。一個典型的例子是使用內存中的數據庫來生成一個數據持久化對象,而不是去訪問一個真正的生產環境的數據庫。
常常,咱們會把Fake Object和Test Stub搞混,由於它們都和外部沒有交互,對內部的輸入輸出也不進行驗證。不一樣的是,Fake Object並不關注SUT內部的間接輸入(indirect inputs)或間接輸出(indirect outputs),它僅僅是用來替代一個實際的對象,而且擁有幾乎和實際對象同樣的功能,保證SUT可以正常工做。實際對象過度依賴外部環境,Fake Object能夠減小這樣的依賴。
mock 與 spy 相似,但在使用上有些許不一樣。spy 追蹤全部的方法調用,並在過後讓你寫斷言,而 mock 一般須要你事先設按期望。你告訴它你指望發生什麼,而後執行測試代碼並驗證最後的結果與事先定義的指望是否一致。