開發人員必備的技能——單元測試

提及軟件測試四個字,想必你們腦海中浮現的有集成測試、系統測試、黑盒測試、白盒測試等,可能就是沒想到會有單元測試。 對於大學是學習軟件工程專業出身的同窗來講可能會聽過這四個字,對工做好幾年的職場老鳥可能也聽過可是沒實際用過居多。絕大多數的開發人員都是忙於把手頭的工做開發好,並不會把單元測試歸入工做範疇,他們會說,我連功能開發都忙不過來了,哪有時間去作單元測試,何況還要寫測試代碼,那不是重複寫一篇代碼功能嗎?但,單元測試真的不值得花時間去作嗎,那是由於可能你並不清楚單元測試的投入產出比有多高,下面就簡單介紹單元測試到底能給開發人員帶來多少好處。html

  • 什麼是單元測試
  • 爲何要作單元測試
  • 不寫單元測試藉口
  • 主流框架 JUnit 和 TestNG
  • Android 中的單元測試
  • 小結

什麼是單元測試

單元測試本質上也是代碼,與普通代碼的區別在於它是驗證代碼正確性的代碼。可簡單作個定義:單元測試是開發人員編寫的、用於檢測在特定條件下目標代碼正確性的代碼。前端

軟件開發天生就具備複雜性,沒人敢打包票說本身寫的代碼一點問題都沒有,或者不經測試就能保證代碼正確運行,可能你在這個執行路徑下可以執行,卻不知還有其餘路徑,有一一去驗證過嗎,所以,要保證程序的正確性就必需要對咱們代碼進行嚴格測試。java

舉個簡單例子:好比有個計算類,裏面有個 add 方法,操做就是兩個數進行相加。android

public class Calculator {
    public int add(int one, int another) {
        //只是簡單的兩個數相加
        return one + another;
    }
}

常規作法:假如你寫好了這個方法,你想進行驗證 add 方法的正確性,須要寫個使用 add 方法的 main 函數,首先實例化 Calculator 類,而後調用 add 方法並傳入兩個參數,好比 1 和 2。而後你運行這個工程,看得出結果是否爲 3 ,若是是 3 ,則代表我這個方法寫的沒有錯誤,可能就不測試了,就繼續開發後續的功能,若是不是 3 ,則返回去看看代碼中哪裏出錯了,從新進行調試,甚至有時候肉眼還看不出代碼哪裏出錯,此時就引入斷點去查看,在此期間,很大一部分時間就花在斷點、調試、運行上。數據庫

單元測試作法:首先會利用 JUnit 測試框架(至於這個框架後面介紹)寫一段測試代碼,以下:編程

public class CalculatorTest {
    public void testAdd() throws Exception {
        Calculator calculator = new Calculator();
        int sum = calculator.add(1, 2);
        Assert.assertEquals(3, sum);
    }
}

這裏的 CalculatorTest 是 Calculator 對應的測試類,這裏的 testAdd 對應着 add 的測試方法,進行測試通常分爲三步驟:數組

  • setup。通常是 new 出你要測試的那個類,好比: Calculator calculator = new Calculator();
  • 執行操做。通常是調用你要測試的那個方法,得到運行結果: int sum = calculator.add(1, 2);
  • 驗證結果。驗證獲得的結果跟預期中是同樣的: Assert.assertEquals(3, sum);

看到 Assert 這個關鍵詞了嗎,這裏能夠理解爲斷言或者指望值,根據入參的值,指望有個什麼值輸出,而不是靠肉眼去驗證是否是本身想要的值,是直接經過判斷值是否相等性來驗證會具備更客觀性。性能優化

以上介紹的只是單元測試一點點,那它能給咱們帶來哪些更多好處呢?數據結構

爲何要作單元測試

一般咱們在作任何工做會先考慮它的回報,編寫代碼更是如此。若是單元測試的做用不大,沒有人會願意再寫一堆無用的代碼,那麼單元測試到底可以給咱們帶來什麼優勢呢?以下:多線程

  • 便於後期重構。單元測試能夠爲代碼的重構提供保障,只要重構代碼以後單元測試所有運行經過,那麼在很大程度上表示此次重構沒有引入新的BUG,固然這是創建在完整、有效的單元測試覆蓋率的基礎上。
  • 優化設計。編寫單元測試將使用戶從調用者的角度觀察、思考,特別是使用TDD驅動開發的開發方式,會讓使用者把程序設計成易於調用和可測試,而且解除軟件中的耦合。
  • 文檔記錄。單元測試就是一種無價的文檔,它是展現函數或類如何使用的最佳文檔,這份文檔是可編譯、可運行的、而且它保持最新,永遠與代碼同步。
  • 具備迴歸性。自動化的單元測試避免了代碼出現迴歸,編寫完成以後,能夠隨時隨地地快速運行測試,而不是將代碼部署到設備以後,而後再手動地覆蓋各類執行路徑,這樣的行爲效率低下,浪費時間。

等等,講了這麼多優勢,無非就是良好的接口設計、正確性、可迴歸、可測試、完善的調用文檔、高內聚、低耦合,這些優勢已經足以讓咱們對單元測試重視起來了,可是我的以爲還有更重要的緣由。

  • 首先,帶來自信。在接手一個新的項目,或者說是參與一個新的項目開發時,每每這種狀況是你半途參加進去的,你須要對已有的代碼結構進行解讀和理解,對於業務的理解,對於代碼箇中各個模塊關係的理解。若是一開始就理財出錯,極可能修改後的代碼會引發更多的BUG出現,到那時候又須要修復更多的BUG,改了一個地方,頗有可能會莫名其妙地影響另一個地方,這種現象是很常見的。還有一種狀況,假設你修改的功能沒問題,可是須要去測試驗證,在測試的時候就須要考慮這個功能點它原有的測試路徑有哪些,又須要一一去驗證功能路徑,以證實本次修改對於已存在的功能點不形成影響。這其中就存在着很大的時間成本,致使效率不高。那是否存在着這麼一種方式,我須要修改我想改動的地方,不須要關心修改完以後它所形成的影響,也不須要關心它的測試迴歸性,有,此時就是單元測試登場的時候。寫單元測試代碼,可讓我本身寫的代碼足夠自信,它是經得起考驗的。
  • 其次,更快反饋。對於有必定編程經驗的開發人員來講,當他拿到一個新需求的時候,首先想到的不是動手 Coding ,而是會先想一想代碼的結構,有些類,數據結構該是如何,而後纔開始敲代碼。若是沒有單元測試,通常流程基本是這個模塊功能所有寫完纔開始測試,好比利用 MVP 架構的功能。通常都是開始 Model 模塊,而後完善 Presenter 模塊,最後寫 View 模塊,等這幾個模塊都寫完了,再把 APP 跑起來,驗證本身寫的功能模塊是否符合需求,沒有符合則繼續回去修改代碼,這中間須要花費很長的時間才能知道當下本身寫的代碼是否符合要求,是否正確。那有沒有一種即時反饋的方式呢,有,寫單元測試便可,當你寫完一個函數,立刻就匹配一個單元測試函數,這樣即寫即測的方式能夠保證你當場寫的代碼立刻進行修改,測試經過一個,就表示完成一個小的功能點,最後,把函數組裝起來,就是咱們想要大的功能點。
  • 最後,節約時間。對於 Android 開發來講,一遍一遍的運行 APP ,而後執行相應的用戶操做,看界面是否正確的顯示,經過這種方式來測試功能,實際上是很是浪費時間,並且效率不高,而用單元測試,能夠幾乎不用打開 APP 來執行,固然有些須要一些資源文件的是須要 APP 運行條件,絕大部分的功能在單元測試階段就能驗證完畢,那麼速度就相對快不少。此外,單元測試還能幫忙減小 BUG ,從而減小調試 BUG 的時間,一些低級犯的錯誤在單元測試階段就能避免掉。

不寫單元測試藉口

不少開發人員不寫單元測試,最重要的一個緣由是他們並不知道單元測試可以帶來什麼好處,甚至根本不瞭解單元測試這個詞,那天然就像平行線般與之毫無交集。還有一個比較重要的緣由是一些開發人員的編程思想還處在一個相對初級的階段,開發軟件只管實現功能,什麼高內聚、低耦合、重構、設計、可測試等認爲太過專業,對於這些名詞以及意義還不瞭解,這天然不會考慮使用了。還有一些非思想層面的理由,以下:

  • 單元測試太花時間了。軟件開發工做那麼忙,代碼都寫不完哪有時間寫單元測試。這多是開發人員用的最多的藉口,從某些方面來講,這不能算藉口,由於不少開發人員確實在工做上投入的時間特別多。但真的是這樣的嗎,你有沒有想過,致使加班的緣由也許就是花了太多時間在手動測試、調試程序上:或許你沒有考慮到靈活性與設計,使得在需求發生變動時你須要花不少時間在複雜的代碼堆中完成特定的功能,而這些修改又可能引入新的 BUG ,又將致使你須要進行耗時的手動測試、調試等等,如此反覆,代碼將變得愈來愈亂,愈來愈難以維護,最終致使無休止的加班。
  • 測試不是個人工做。測試確實不是開發人員的工做,但單元測試確實是開發人員的工做,測試包含不少種,而只有單元測試是開發人員的工做範疇。開發人員爲應用編寫代碼,那麼天然須要保證代碼的正確性,而單元測試正是這種保證代碼正確性的白盒測試,也就是在瞭解代碼內部結構邏輯的狀況下進行有目的的測試,既然說到了解代碼,那麼開發者天然是最權威的人。所以,編寫單元測試而且爲測試人員提交正確的代碼進行其餘測試是開發人員的職責所在。
  • 代碼都編譯經過了,還測什麼。通常來講,這是一個不會放在嘴上但可能藏在內心的藉口。代碼編譯經過只能說你寫的代碼符合語法要求,並不表明能保證正確性。
  • 代碼原來就沒有單元測試,而且難以測試。這個問題基本是接受和維護別人開發的代碼,而原來的代碼自己就沒有單元測試了,再加入若是代碼的耦合性較高,那麼就更難覺得這些代碼寫單元測試。此時正是你瞭解代碼時候,首先爲可以測試的部分添加單元測試,保證這些可測試的部分不會被污染,而後在對代碼有足夠的瞭解以後再對代碼進行重構,下降代碼的耦合性,而且慢慢補充測試用例,使得代碼的耦合性、可測試性慢慢創建起來。

主流框架 JUnit 和 TestNG

JUnit 是一個 Java 語言的單元測試框架,它是 xUnit 單元測試架構體系的一個實例,用於編寫和運行可重複的測試。它包括如下特性:

  • 用於測試指望結果的斷言(Assertion)
  • 用於共享共同測試數據的測試工具
  • 用於方便的組織和運行測試的測試套件
  • 圖形和文本的測試運行器

TestNG 是一個測試框架,其靈感來自 JUnitNUnit ,但引入了一些新的功能,使其功能更強大,使用更方便。TestNG 消除了大部分的舊框架的限制,使開發人員可以編寫更加靈活和強大的測試。 由於它在很大程度上借鑑了Java註解( JDK5.0 引入的)來定義測試,它也能夠顯示如何使用這個新功能在真實的Java語言生產環境中。

特色以下:

  • 註解
  • TestNG 使用 Java 和麪向對象的功能
  • 支持綜合類測試(例如,默認狀況下,不用建立一個新的測試每一個測試方法的類的實例)
  • 獨立的編譯時測試代碼和運行時配置/數據信息
  • 靈活的運行時配置
  • 主要介紹「測試組」。當編譯測試,只要要求 TestNG 運行全部的「前端」的測試,或「快」,「慢」,「數據庫」等
  • 支持依賴測試方法,並行測試,負載測試,局部故障
  • 靈活的插件 API
  • 支持多線程測試

Android 中的單元測試

由於 JUnit 測試框架是基於 Java 語言,固然 Android 開發也是基於 Java 語言,因此在 Android 中咱們能夠用 Junit4 單元測試框架進行迴歸測試,但同時,Google 也提供了一個 AndroidJUnit4 測試框架,看名字就知道它是基於 JUnit 4 框架適合在 Android 環境中作單元測試。

那麼,AndroidJUnit4 和 Junit4 有什麼區別呢?很大一個區別在於:

1,AndroidJUnit4 測試能夠在真機的環境下進行。好比你要測文件讀取SD卡,或者操做 SqlLite 數據庫,這些條件只有在真機上纔有的,此時你用 AndroidJUnit4 框架測試,能夠直接跑起來用真實的環境作相應的單元測試。

2,JUnit4 測試是運行在工程項目中,也就是在編譯階段。此時若是想要模擬 Android 環境,好比我想用 JUnit4 來測試 Activity 類,那麼就須要引用第三方庫來支持,引用 Mockito 和 Robolectric 框架來模擬 Android 環境進行相應的單元測試。

因此什麼時候用 AndroidJUnit4 和 JUnit4 不一樣的框架進行單元測試,就看你待測試的方法前置條件是什麼,而後作不一樣的選擇。

小結

總的來講,單元測試不是集成測試,單元測試只是測試一個方法單元,不是測試一整個流程。集成測試是一種End To End的系統測試,測試相關模塊集成在一塊兒是否可以按照預期工做,通常都是接口或者功能層面的測試,可能會依賴不少系統因素,測試的代碼邏輯通常比較複雜,運行時間會比較長,出錯以後的修復成本高。單元測試則是開發者在集成測試以前就已經進行自測過,同時呢,進行單元測試以後,對於某個方法的執行路徑組合進行了一一驗證,它只關注三個目標:

  • 有明確的返回值。好比對某個函數進行單元測試,驗證其返回值是否符合預期結果。
  • 這個函數只改變其對象內部的一些屬性或者狀態,函數自己沒有返回值,就驗證它所改變的屬性和狀態。
  • 一些函數沒有返回值,也沒有直接改變哪一個值的狀態,這就須要驗證其行爲,好比點擊事件。

閱讀擴展

源於對掌握的Android開發基礎點進行整理,羅列下已經總結的文章,從中能夠看到技術積累的過程。
1,Android系統簡介
2,ProGuard代碼混淆
3,講講Handler+Looper+MessageQueue關係
4,Android圖片加載庫理解
5,談談Android運行時權限理解
6,EventBus初理解
7,Android 常見工具類
8,對於Fragment的一些理解
9,Android 四大組件之 " Activity "
10,Android 四大組件之" Service "
11,Android 四大組件之「 BroadcastReceiver "
12,Android 四大組件之" ContentProvider "
13,講講 Android 事件攔截機制
14,Android 動畫的理解
15,Android 生命週期和啓動模式
16,Android IPC 機制
17,View 的事件體系
18,View 的工做原理
19,理解 Window 和 WindowManager
20,Activity 啓動過程分析
21,Service 啓動過程分析
22,Android 性能優化
23,Android 消息機制
24,Android Bitmap相關
25,Android 線程和線程池
26,Android 中的 Drawable 和動畫
27,RecylerView 中的裝飾者模式
28,Android 觸摸事件機制
29,Android 事件機制應用
30,Cordova 框架的一些理解
31,有關 Android 插件化思考
32,開發人員必備技能——單元測試

相關文章
相關標籤/搜索