天天看點

在 MVP 中進行單元測試0. 提綱1. 什麼是單元測試2. 單元測試的意義3. Android 開發中進行單元測試4 開源架構5. MVP 架構中如何寫單元測試6. 例子

對于測試,大家都不陌生,但是我相信還是有部分開發覺得測試工作和自己沒有直接關系、測試工作是測試工程師的事。慚愧的說,本人也是很長一段時間内沒真正了解“測試”這件事兒,之前呆過的幾家公司都沒有真正的“測試工程師”,确切的說,是沒有會寫代碼的測試工程師,基本上都是手動測試,然後輸出報告,測試無需懂技術,我相信國内很多公司都是這樣,特别是 app 端的測試,很少有白盒測試的。這篇要說的東西不多,主要來說說單元測試,由于本人也是最近才開始實踐,文章抛磚引玉,如果有說得不到位的地方,希望讀者給予指正。

0.1 什麼是單元測試

0.2 單元測試的意義

0.3 android 開發中進行單元測試

0.3.1 androidstudio 中配置

0.4 開源架構

0.5 mvp 架構中如何寫單元測試

0.6 例子

我們先來做這麼一個體驗。假設現在我們有個開發者要完成某個功能的開發,現在我們從電腦螢幕的視角來觀察他接下來的一序列行為:

在這個觀察中,我們看到他每次啟動運作 a 所做的事其實就是“測試”,是以單元測試這件事其實是每個開發都做得最多的一件事,隻是怎麼讓這件事變得更高效、更有意義是接下來要講的。最後給出一個官方性的定義:單元測試又稱為子產品測試, 是針對程式子產品(軟體設計的最小機關)來進行正确性檢驗的測試工作。 程式單元是應用的最小可測試部件。

我們先來看看一張圖:

在 MVP 中進行單元測試0. 提綱1. 什麼是單元測試2. 單元測試的意義3. Android 開發中進行單元測試4 開源架構5. MVP 架構中如何寫單元測試6. 例子

這張圖叫做測試金字塔,單元測試處于開發環節比較早期,粒度也比較小,也是最重要的一個環節,對整體測試的效率至關重要,這部分做好了,後期的測試才會更有效,試想如果整棟樓建好了才發現磚頭品質有問題,那是多麼糟糕的事;單元測試就像對每個螺絲釘測試一樣,生産螺絲釘的時候發現螺絲釘有問題很容易解決,如果在機器運轉故障的時候去定位是不是螺絲釘、具體是那顆螺絲釘就難了。單元測試的意義可以總結如下幾點:

代碼品質的基礎保障。

單元測試,子產品區間比較小,更容易發現問題,發現問題更容易定位。

為後期內建測試節省了很多時間。

單元測試是對程式結構的一個觀察者視角審視,有利于我們提高代碼的整體設計能力。

android 為我們提供了兩種跑測試的方式:

unit tests

android instrumentaion tests

在 MVP 中進行單元測試0. 提綱1. 什麼是單元測試2. 單元測試的意義3. Android 開發中進行單元測試4 開源架構5. MVP 架構中如何寫單元測試6. 例子

unit tests 這種方式,跑的測試代碼運作在本機 jvm 上,不需要編譯apk ,不需要 android 裝置的支援,速度相對快,當然,測試的對象不能含有 android 的 api,否則運作時會報錯。這個模式下,測試代碼的預設路徑是 test/java。單元測試的基礎架構是 junit,需要配置依賴:

然後我們來寫一個被測試類:calculator.java

把test artifact 切換到 unit tests 模式,然後我們建立一個針對這個類的測試:calculatortest.java

在 MVP 中進行單元測試0. 提綱1. 什麼是單元測試2. 單元測試的意義3. Android 開發中進行單元測試4 開源架構5. MVP 架構中如何寫單元測試6. 例子

選擇 create new test

在 MVP 中進行單元測試0. 提綱1. 什麼是單元測試2. 單元測試的意義3. Android 開發中進行單元測試4 開源架構5. MVP 架構中如何寫單元測試6. 例子

自動生成了選擇的測試方法,@before、 @after、@test 這幾個注解來自 junit 的 api,@before 标記的方法,在測試用例啟動時最先執行,然後執行 @test 标記的方法,最後執行 @after 标記的方法。一般會在 @before 的方法中做初始化工作,例如:建立被測試的對象, @test 标記的就是我們要測試的方法,在其中執行驗證方法。完善我們的測試代碼:

然後在這個類上右鍵,我們就可以運作這個測試類了。

android instrumentaion tests 包的測試代碼運作在 android 裝置上,速度相對慢一些。測試代碼預設路徑是 androidtest/java。為了讓測試能跑在裝置上,需要 androidjunitrunner 的支援:

配置依賴:

同時也離不開 junit 的支援,配置依賴:

建立測試和 unit tests 的一樣,運作的時候需要連接配接模拟器或手機。

測試架構很多,這裡隻簡單說說比較流行的組合以及本例子中要使用的架構:

espresso:google 提供的 u i測試架構。

了解了 androidstudio 中如何寫最基本的單元測試,再結合幾個開源架構,我們可以來寫一些更為貼近實際開發的測試用例了。 目前 mvp 是 android 項目的比較流行的架構模式,它的優點在代碼的易測性

上也得到了極好的展現,對 mvp 不熟悉的考驗參考我之前的幾篇部落格:

<a href="http://www.jianshu.com/p/e157cc64ea5c">android 應用架構概述</a>

<a href="http://www.jianshu.com/p/101f756bf3b8">android應用架構之mvp實作</a>

對于 mvp 個層次我們怎麼來寫測試代碼? 先來看看架構的選型:

view層

view的測試自然依賴于android環境,同時需要模拟u互動的能力,使用 espresso + junit,espresso用于模拟和驗證各種各樣的ui操作,使用 android instrumentaion tests 運作,代碼存放于androidtest中。

presenter層

presenter 上對ui,下對 model 都是接口抽象,控制流程邏輯,不涉及 android api,用 junit + mockito 測試即可,使用 unit tests 運作,代碼存放于test中。

model層

負責資料的存取,資料可能來自于網絡、資料庫和記憶體,如果涉及裝置相關的api、依賴android系統環境,則使用 android instrumentaion tests 運作,代碼存放于androidtest中;反之可以junit+mockito,使用 unit tests 運作,代碼存放于test中。

## 6.1 場景介紹

這是一個簡單的場景,一個遊戲清單頁面。對于清單頁面,通常都會有緩存邏輯,加載資料時會優先去加載本地資料,如果沒有,則加載遠端資料。本例使用 mvp 來架構這個簡單的場景(引入了 eventbus 來代替正常的異步回調,eventbus 極其簡單,不過不了解也不影響對本章主題的了解),然後真對 m 和 p 分别寫了對于的單元測試,本例沒有寫 view 層的單元測試(個人覺得對 view 寫單元測試的必要性不大,如果你的感受相反,非常感謝你給我一個說服我的理由),我們先來流程圖:

在 MVP 中進行單元測試0. 提綱1. 什麼是單元測試2. 單元測試的意義3. Android 開發中進行單元測試4 開源架構5. MVP 架構中如何寫單元測試6. 例子
在 MVP 中進行單元測試0. 提綱1. 什麼是單元測試2. 單元測試的意義3. Android 開發中進行單元測試4 開源架構5. MVP 架構中如何寫單元測試6. 例子

test/java :該目錄下寫了針對 gamepresenter 的單元測試 gamepresentertest 和針對 gamemanager 的測試類 gamemanagertest (這個跑不過,因為涉及類 android 的 api)

androidtest / java: 該目錄下寫 針對 gamemanager 的測試類 gamemanagerandroidtest (邏輯和 gamemanagertest 一樣)

@mock :對成員變量的注解,被這個注解的變量不用手動執行個體化,mockito 會幫你注入一個模拟的對象(需要在 @before 标記的方法中先執行 mockitoannotations.initmocks(this)。例如:

初始化 mockitoannotations

verify(t):這是 mockito api 提供的一個靜态方法,用來驗證某個 mock 對象(@mock 标記的對象)是否執行了某個方法,執行了多少次。verify(t),傳回是一個泛型,你傳入什麼類型他就傳回什麼類型的子類給你,重寫的方法中驗證傳入對象對應的方法是否執行過。例如:

//驗證 gamelistview.showloading() 是否執行

when(object.method()).thenreturn(returnobject): 這是 mockito api 提供的一個靜态方法,用來改變方法的對象的行為(方法),當 object.method() 調用的時候傳回 returnobject ,用來模拟方法的傳回值。例如本例中模拟擷取本地資料為空:

繼續閱讀