mock +springboot 測試基本概念

wwwh 法則 what,why,when, how


what

說在前面

測試分類

(技術類型):單元測試->接口測試->UI測試,這可能是比較常見的測試金字塔( unit->api->ui )

(系統分層或測試階段):單元測試->組件測試->集成測試->系統測試

(是否測試代碼):黑盒,白盒,灰盒

(是否運行):靜態測試,動態測試


單元測試:是對軟件中的最小單元進行測試和驗證,通俗來講就是代碼中的一個函數或一個類,單元測試一定是白盒測試
單元測試通常由開發工程師完成一般會伴隨開發代碼一起遞交至代碼庫。單元測試屬於最嚴格的軟件測試手段,是最接近代碼底層實現的驗證手段,可以在軟件開發的早期以最小的成本保證局部代碼的質量

Test Pyramid理論基本大意是,

單元測試是基礎,是我們應該花絕大多數時間去寫的部分,

而集成測試等應該是冰山上面能看見的那一小部分。


why:

  • 軟件質量最簡單、最有效的保證;
  • 是目標代碼最清晰、最有效的文檔;
  • 可以優化目標代碼的設計;
  • 是代碼重構的保障;
  • 是迴歸測試和持續集成的基石。

普通的單元測試
進行單元測試時,我們只需關心三樣東西:
1.設置測試數據
2.設定預期結果
3.驗證結果


when 
在項目中如何進行單元測試考量?

  1. 項目適合不適合進行單元測試
  2. 項目中哪些模塊適合單元測試
  3. 選用什麼樣的單元測試框架
  4. 如何執行單元測試
  5. 如何將單元測試融入ci進行持續集成

基於上面的考慮,如何在項目中開展單元測試。
並不是所有的項目都適合進行單元測試,即使進行單元測試,也應該是一些基礎底層模塊或者核心模塊進行單元測試
選擇合適的單元測試框架,Java中的TestNG、JUnit,Python中的Unittest、Pytest,PHP中的PHPUnit
將單元測試集成到CI流程當中


how:
等價類劃分法:case設計方法:
邊界值法:針對不同分類的case再進行邊界參數case設計
針對代碼實現的邏輯,應當根據產品業務邏輯進行預期的輸入輸出設計,而不能根據代碼進行相關設計,那就沒什麼用了

樁代碼(stub)和mock
單元測試是測試軟件的最小單元,它應該是與軟件其他部分相分隔,例如與真實的數據庫、網絡環境等分隔開的,從而只測試我們關心的邏輯部分。那麼對於有外部依賴的單元如何進行測試呢?這裏提到兩個概念:樁代碼和mock

樁代碼:用來代替真實代碼的臨時代碼,對於依賴的其它部分直接使用固定代碼或固定數據返回,屬於完全模擬外部依賴
mock:這個就很常見了,它的作用也是替代真實的代碼或者數據,與樁代碼不同的是,mock還是可以進行相關的規則制定,還需要關心mock函數的調用和返回數據,例如mock的多次調用是否異常等等。mock用來模擬一些交互進行一些斷言判斷測試是否通過。
但是兩者都是爲了對被測試函數進行隔離和補齊。


單元測試場景實例:

假設我們有一段業務邏輯,需要對給定的請求做處理,在這種情況下,倘若要手工構造發起一個請求,那想必是很麻煩蛋疼。首先我們需要把代碼編譯部署到測試服務器上,然後構造併發起一個請求,等待服務器接收到請求後,交給我們的業務進行處理。如下:

// 業務代碼
public boolean handleRequest(HttpServletRequest request) {
    String module = request.getParameter("module");
    if ("live".equals(module)) {
        // handle module live request
        return true;
    } else if ("user".equals(module)) {
        // handle module user request
        return true;
    }
    return false;
}

爲了測試這麼一點點代碼,就需要我們額外付出那麼多的操作,對於追求效率的程序員來說,這種重複操作&等待簡直就是慢性自殺。這裏的代碼還是相對簡單的,要是請求的內容更加複雜,難道還要花上大把時間研究如何構造出這麼一個Http請求嗎?

其實,測試這段邏輯,我們想要做的事情其實很簡單,給定一個特定的輸入,驗證其輸出結果是否正確。也就是,驗證的過程,應該儘可能的簡單方便,把大部分的時間耗費在驗證過程上絕對是有問題的。

如果我們使用單元測試,搭配Mockito,完全可以寫出如下測試,在代碼提交之前,先在本地的JVM上過一遍測試。

結合Mockito+單元測試

@Test
public void handleRequestTestLive() throws Exception {
    HttpServletRequest request = mock(HttpServletRequest);
    when(request.getParameter("module")).thenReturn("live");
    
    boolean ret = handleRequest(request);
    assertEquals(true, ret)
}

@Test
public void handleRequestTestUser() throws Exception {
    HttpServletRequest request = mock(HttpServletRequest);
    when(request.getParameter("module")).thenReturn("user");
    
    boolean ret = handleRequest(request);
    assertEquals(true, ret)
}

@Test
public void handleRequestTestNone() throws Exception {
    HttpServletRequest request = mock(HttpServletRequest);
    when(request.getParameter("module")).thenReturn(null);
    
    boolean ret = handleRequest(request);
    assertEquals(false, ret)
}

首先,我們模擬出一個假對象,並設定這個假對象的行爲,這個假對象的行爲會影響我們業務邏輯的結果,所以我們可以在不同的測試用例裏,設定假對象返回不同的行爲,這樣我們就能驗證各種輸入下,我們的業務邏輯是不是能夠按我們的設想正常工作

有關於:Mock

Mock一詞指效仿、模仿,在單元測試裏,使用mock來構造一個“替身”。這個替身主要用於作爲被測類的依賴關係的替代。

依賴關係 – 依賴關係是指在應用程序中一個類基於另一個類來執行其預定的功能.依賴關係通常都存在於所依賴的類的實例變量中.

被測類 – 在編寫單元測試的時候, “單元”一詞通常代表一個單獨的類及爲其編寫的測試代碼. 被測類指的就是其中被測試的類.

爲什麼需要mock呢?

真實對象具有不可確定的行爲,產生不可預測的效果,(如:股票行情,天氣預報
真實對象很難被創建的
真實對象的某些行爲很難被觸發
真實對象實際上還不存在的(和其他開發小組或者和新的硬件打交道)等等
在這些情形下,使用Mock能大大簡化我們的測試難度。舉個例子:

假定我們有如上的關係圖:
類A依賴於類B和類C
類B又依賴於類D和類E
爲了測試A,我們需要整個依賴樹都構造出來,這未免太麻煩

使用Mock,就能將結構分解,像這樣。從圖中可以清晰的看出,我們的依賴樹被大大的簡化了。Mock對象就是在測試的過程中,用來作爲真實對象的替代品。使用了Mock技術的測試,也就能稱爲Mock測試了。

使用Mock和Stub(打樁)的好處

  1. 提前創建測試,比如進行TDD
  2. 團隊可以並行工作
  3. 創建演示demo
  4. 爲無法/難以獲取的資源編寫測試
  5. 隔離系統
  6. 作爲模擬數據交付給用戶(假數據)

 

集成測試

接觸單元測試的時候,一直很迷惑,我的業務邏輯那麼多那麼複雜,這要怎麼做單元測試呢?比如說一個登陸功能,雖然它僅僅是一個登陸功能,但它背後要乾的事情可不少:驗證用戶名,驗證密碼,判斷網絡,發起網絡請求,等待請求結果,根據結果執行不同的邏輯。

想想都頭大,這樣的單元測試要怎麼寫?

答:這樣的單元測試不用寫。

我們給這個東西做測試的時候,不是測整個登陸流程。這種測試在測試領域裏稱爲集成測試,而不是單元測試。

集成測試並不是我們(程序員)花精力的地方,而的是測試同事的業務範圍

 

集成測試設置起來很麻煩,運行起來很慢,發現的bug少,在保證代碼質量、改善代碼設計方面更起不到任何作用,因此它的重要程度並不是那麼高,也無法將它納入我們正常的工作流程中。

而單元測試則剛好相反,它運行速度超快,能發現的bug更多,在開發時能引導更好的代碼設計,在重構時能保證重構的正確性,因此它能保證我們的代碼在一個比較高的質量水平上。同時因爲運行速度快,我們很容易把它納入到我們正常的開發流程中。

至於爲什麼集成測試發現的bug少,而單元測試發現的bug多,這裏也稍作解釋,因爲集成測試不能測試到其中每個環節的每個方面,某一個集成測試運行正確了,不代表另一個集成測試也能運行正確。而單元測試會比較完整的測試每個單元的各種不同的狀況、臨界條件等等。一般來說,如果每一個環節是對的,那麼在很大的概率上,整個流程就是對的。雖然不能保證整個流程100%一定是對的。所以,集成測試需要有,但應該是少量,單元測試是我們應該花重點去做的事情

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章