TDD學習筆記【二】---單元測試簡介

大綱

Testing 的第一個切入點:單元測試。數據庫

本篇文章將針對單元測試進行簡介,主要內容包含了5W:網絡

  1. Why
  2. What
  3. Where
  4. Who
  5. When

而How 的部分,屬於實現部分,將於下一篇文章介紹工具與簡單的範例。工具

最後會提到測試用例所表明的意義與其重要性。post

前言

單元測試,是開發人員最該寫的測試程序,卻也是最容易被忽略的測試。單元測試

你們常碰到的測試相關問題是:學習

  1. 每每一堆人寫測試程序時,自覺得是在寫單元測試,卻壓根就不是單元測試,而是集成測試。
  2. 生產代碼是我寫的,若是測試程序也是我寫,那有什麼意義?因此應該給QA/QE 來寫才能測出盲點。
  3. 我程序都寫完了,跑起來也都對,這時寫測試程序一點意義都沒有。
  4. 測試程序要跑很久。
  5. 沒有測試環境,要怎麼寫測試。

看完這幾篇單元測試的相關文章後,但願你們能夠得到一些想法,解決這些問題。測試

Why

先舉幾個在開發上常見的問題:spa

  1. 怎麼讓UI, Service, Data Access 平行開發?
  2. 要到真實環境方能測試程序無誤
  3. 頁面發生錯誤,究竟是誰錯了?
  4. 交付的程序,到底測過哪些東西了?
  5. 我改了這支程序,會不會害別的程序掛掉?

這些問題,能夠有哪些Unit Test 相關的方式來解決:設計

  1. Unit Test 中使用stub/mock object,達到關注點分離
  2. Unit Test 使用stub/mock object 來模擬外部回傳的數據
  3. 把input 值當作test case,跑一次Unit Test
  4. 交付的程序,包括Unit Test 程序
  5. 改完程序就跑一次Unit Test 吧

總而言之,沒有被測試涵蓋到的程序,即便它多是對的,也沒人敢拍胸脯保證。而有了測試用例來輔助說明與保護,至少能夠拍胸脯保證,在這樣的測試用例下,這個對象的設定,確定如同預期般執行。3d

而單元測試能夠提供迴歸測試的保護,在每一次異動完程式,能夠單鍵執行就知道是否破壞了本來對對象行爲的預期。

單元測試能夠透過一些輔助設計,來達到與外部環境、服務、相依隔絕,而僅測試該物件自己的邏輯,以及與外部的互動是否符合預期。

形成問題的測試案例,每每是最珍貴的,由於最具表明性,也最具價值。由於它提供了咱們修正bug的方向以及指標。而針對發生問題的測試案例,來執行單元測試,立刻就能夠知道是不是該對象的內部問題。

最後,單元測試因爲具有與外界服務、相依隔絕的特性,因此能夠幫助撰寫實際的對象時,具備可測試性、低耦合性,彼此之間只相依於抽象或接口。進而經過IoC 的設計,讓咱們能夠作到關注點分離,讓開發各個對象的developer,能夠透過接口來溝通,不相依於彼此實現,就能平行開發。

What

Unit Test 的定義與基本準則,以下圖所示:

  1. 一個測試案例只測一種方法
  2. 最小的測試單位
  3. 不與外部(包括項目、數據庫、網絡、服務、對象、類型)直接相依
  4. 不具有邏輯
  5. 測試案例之間相依性爲零

Unit Test的特性,一個字:FIRST。以下圖所示:

  1. Fast:快速。
  2. Independent:獨立。
  3. Repeatable:可重複。
  4. Self-Validating:可反應驗證結果。單元測試不論成功或失敗,都應該要從測試的reporting 直接瞭解其意義或失敗緣由。
  5. Timely:及時。單元測試應該剛好在使其經過的production code 以前撰寫。

 即:優良的單元測試具備如下的特色:簡稱爲 A-TRIP。    

  • 自動性(Automatic)
  • 完備性(Thorough)
  • 可重複性(Repeatable)
  • 獨立性(Independent)
  • 專業性(Professional)

Where

單元測試的覆蓋範圍,以定義來講,單元測試是最小的測試單位,在面向對象中,就是測試一個方法。而方法必定會在某個對象上(即便是靜態方法,也是在類型對象上)。

因此,單元測試一般就只關注在測試的目標對象上,而無論目標對象之外的東西,例如:目標對象所相依的實體對象、相依服務、相依資源、相依環境等等...

單元測試,簡單的說,就是用來模擬外部如何使用這個目標對象,或是如何與這個目標對象互動。因此咱們所撰寫的單元測試程序,就是模擬與目標對象互動的程序。測試案例,就是該互動下的情境。接着驗證物件的行爲是否符合咱們預期。

所以,單元測試程式,既然是模擬外部如何使用目標物件,因此也只會針對目標對象對外開放的方法。

而基本上,單元測試透過哪些方式去驗證對象的行爲符合預期呢?簡單來講,有三種:

  1. 驗證目標對象的回傳值,以下圖所示:
  2. 驗證目標對象的狀態改變,以下圖所示:
  3. 驗證目標對象與外部相依接口的互動方式,以下圖所示:

 

Who

單元測試該由誰來撰寫,就如同前言所說,最應該撰寫的是developer,而非QA/QE。

就如Where段落所說,單元測試簡單的說,是咱們在設計對象的時候,預期外部該如何使用這個對象,進而衍生出對象該提供什麼樣的功能、具有什麼樣的行爲。正由於對象的設計人、使用人,都是developer,因此單元測試的程式,固然由developer來設計,最爲穩當。尤爲由用的人來寫,最爲精準。

概括幾個基本要點:

  1. 想要達到什麼需求,就是測試案例。而對象的設計,只是爲了知足需求,需求即測試案例。即生產代碼只爲了知足測試程序上的測試案例。
  2. 設計對象的人員,才能知道對象該怎麼給外面使用。
  3. 由外部使用對象的角度來設計測試案例。

When

撰寫單元測試的時機點,簡單​​分紅三個:

  1. 外部須要使用對象,並對其執行結果有所預期時( developing )
  2. feature的異動時( modifying )
  3. 出現非預期執行結果時( bug fixing )

想清楚,外部的需求是什麼,才能設計出符合需求的對象。

當需求異動時,天然須要針對新的需求,來設計新的測試程序,由於這樣才能驅使目標物件行爲的改變。

當出現非預期的執行結果時,一般表明目標物件有着非預期的行爲發生,有多是當初測試案例不足,因此要增長咱們的「預期」。

也有多是當初預期的結果就錯了,那其實就能夠看成是第二點,需求的異動。(固然對使用端來講,仍是屬於bug,但對對象設計來講,測試案例方向就錯了)

Test Cases的意義

你們買過3C產品或電器吧,基本上拿到一個東西,咱們都會先看使用說明書。

你們確定也寫過一堆「系統分析書」、「代碼規格書」、「SA/SD 文件」等等...但這些文件,跟最後線上的代碼,究竟有多少是相同的呢?文件越詳細,表明後面修改的effort 越大。

由於軟件設計,原本就是個需求頻繁變更的過程,每每你們只想「凍結需求」,卻很常由於「凍結需求」搞到做出來的系統難用,由於不符合使用者需求。

咱們指望的是,每一次的需求異動,都是軟​​件進化的動力,每一次的異動,都是品質的累積,以及更符合使用者的需求。

而文件呢?只有一開始分析、設計爽的,由於代碼寫下去,跟文件搭不搭的起來,只有三我的知道,一個已經離職了,一個是我,另外一個我不能說。

鮮少會有文件跟着代碼一直進行更新的。

但文件卻又是輔助瞭解與說明很重要的東西,那怎麼辦?很簡單,會一直活着的,就只有代碼。要驗證代碼是否符合咱們預期,最簡單的方式,就是用代碼驗證它的行爲,一翻兩瞪眼,如今的物件究竟知足了那些功能,哪些情境下能夠跑出預期結果,測試案例一目瞭然。

因此,測試案例的意義與價值是什麼?

  1. 可自動執行、立刻執行、快速執行的對象使用說明書,不會有過時或漏了更新的問題。
  2. 無論什麼狀況發生,無論在什麼環境底下,都能確保其執行結果如同預期。

代碼即文件,高興何時產生文件,就何時產生,保證即時、可運做、童叟無欺。測試案例上面有的,確定work,而測試案例上面沒有的,不必定會錯,但不打包票。

 

小結

一句話總結:「Working software is based on working test cases」。

Working software 是TDD 的整個骨架,也是user 最須要的東西。

 備註:這個系列是我畢業後時隔一年從新開始進入開發行業後對大拿們的博文摘要整理進行學習對自個人各個欠缺的方面進行充電記錄博客的過程,非原創,特此感謝91 等前輩

相關文章
相關標籤/搜索