測試泛談

1. 前言

軟件測試可能是個做開發的都知道,一般的項目都有測試人員做系統測試,至於集成測試和單元測試可能就沒多少人寫,這個跟公司開發流程和開發人員自身的編碼習慣有關,也沒什麼好與壞之分。

就我個人而言,我是對測試比較感興趣的,完善的測試開發流程是能夠提高團隊寫代碼的效率和保障代碼質量的。我自己寫代碼一般會寫單元測試,感覺還是有點效果的,最少提交代碼時心裏都比較有底氣。不過我對測試的瞭解還是很少,僅僅是知道一些皮毛,所以這次抽空看了敏捷開發相關的開發流程和思想,瞭解測試驅動的開發和業務驅動開發,受益匪淺。這篇文章就記錄一下我對測試的一些理解,當然主要講跟開發人員比較相貼合的單元測試和集成測試。

2. 軟件測試分類及其特徵

既然講測試,就先要了解什麼是軟件測試,這裏引用百度百科的定義:在規定的條件下對程序進行操作,以發現程序錯誤,衡量軟件質量,並對其是否能滿足設計要求進行評估的過程。詳情看這裏:軟件測試

軟件測試有很多,一般會對對軟件測試進行分類,方便理解和記憶。這裏引用wiki對軟件測試的分類 Software testing

  • 以開發階段劃分
    • 單元測試、集成測試、接口測試、系統測試、驗收測試
  • 以代碼可見性劃分
    • 白盒測試、黑盒測試、灰盒測試、動態測試、靜態測試
  • 以測試類型劃分
    • 冒煙測試、迴歸測試、A/B測試、兼容性測試、性能測試、併發測試 一共19種,不再贅述

對於開發人員來說,比較熟悉的測試類別應該是以開發階段來劃分的各個測試,這裏做一個比較詳細的介紹吧:

單元測試(Unit Testing)

單元測試是對軟件組成單元進行測試,其目的是檢驗軟件基本組成單位的正確性。

  • 測試階段: 編碼後
  • 測試對象:函數
  • 測試人員:開發人員
  • 測試方法:白盒測試
  • 測試內容:接收參數的邊界值和類型,進行輸入時輸出是否符合預期,錯誤處理等

集成測試(Integration Testing)

集成測試也稱聯合測試、組裝測試,將程序模塊採用適當的集成策略組裝起來,對系統的接口及集成後的功能進行正確性檢測的測試工作。主要目的是檢查軟件單位之間的接口是否正確。

怎麼理解呢,這裏打個比方,比如在一個Web服務器中,測試控制層(controller)的接口可以看做是一個簡單的集成測試,因爲在控制層中會使用到服務層、數據持久層等多個方法,達到了將其他模塊一起聯合測試的效果

  • 測試階段: 單元測試後
  • 測試對象:模塊間的接口
  • 測試人員:開發人員
  • 測試方法:白盒測試和黑盒測試
  • 測試內容:模塊間的數據傳輸、模塊組裝的功能完整性和正確性、單模塊缺陷時對系統的影響等

系統測試(System Testing)

將軟件系統看成是一個系統的測試。包括對功能、性能以及軟件所運行的軟硬件環境進行測試。時間大部分在系統測試執行階段

比較常見的就是測試人員模擬用戶行爲在頁面、終端上進行操作

  • 測試階段: 集成測試後
  • 測試對象:整個系統
  • 測試人員:測試人員
  • 測試方法:黑盒測試
  • 測試內容:功能、界面、可靠性、易用性、性能、兼容性、安全性等

驗收測試(Acceptance Testing)

驗收測試是部署軟件之前的最後一個測試操作。它是技術測試的最後一個階段,也稱爲交付測試。驗收測試的目的是確保軟件準備就緒,按照項目合同、任務書、雙方約定的驗收依據文檔,向軟件購買都展示該軟件系統滿足原始需求。

  • 測試階段:系統測試通過之後
  • 測試對象:整個系統(包括軟硬件)。
  • 測試人員:主要是最終用戶或者需求方。
  • 測試依據:用戶需求、驗收標準
  • 測試方法:黑盒測試
  • 測試內容:同系統測試(功能…各類文檔等)

3. 系統分層測試

上面講述了關於測試的分類和詳細的介紹了以開發階段劃分的測試。那麼,在一個項目中,在不同階段,不同的模塊,不同的層次中使用的測試方法是不一樣的,稍後我將以我做的系統做一個分層的例子。

將項目分層,對各層次進行抽象剝離,針對不同層次做不同的測試。每個層次不需要知道其他層次的實現邏輯,只需要關注當前層次業務邏輯,對於其他層次,可以認爲其業務邏輯都正確,在此基礎上寫相關測試。

目前我接觸的web項目中,業務都是比較簡單的,所以我就簡單的對整個系統做一個分層處理,如下:
在這裏插入圖片描述
項目都是前後端分離的,所以我將它分成了兩大模塊,前端和服務端,它們之間通過HTTP通信。

因爲我是做服務器開發的,前端相關的編碼和測試我只是稍微瞭解過,我個人知道的是前端也有對應的單元測試,針對UI的mock測試以及集成測試等,其他的瞭解不多,就不再闡述。個人感覺前端UI測試的付出比較高、收益相對較低。

在服務端,因爲採用的是傳統的MVC架構,所以直接以MVC架構對其分層:

  • 控制層(controller)
  • 服務層(service)
  • 數據持久層(dao)
  • 其他工具工具類和輔助模塊

對上述的服務端中,各個層次使用的測試方法可能有所不同:

  • 控制層:單元測試、集成測試
  • 服務層:單元測試
  • 數據持久層:單元測試
  • 其他模塊:單元測試

通常工具類可以很方便的使用單元測試進行校驗,因爲它不依賴其他業務代碼,但業務邏輯代碼的單元測試就要稍微複雜一些,因爲可能會頻繁的使用其他模塊的功能和方法。

web服務器中可以直接調用API接口作爲集成測試,這是相當的方便了。當然,也可以根據不同的需求編寫其他的集成測試。

4 單元測試

單元測試,一般而言就只是測試一個函數模塊,通過傳入不同的參數來測試模塊的處理結果是否符合預期。

寫單元測試,當要調用其他層次和工具的方法時,要相信它們是正確的。如果數據需要其他層次或工具處理並返回時,可以使用mock技術對使用的方法進行數據模擬處理並返回期望值。

4.1 使用mock技術

mock測試就是在測試過程中,對於某些不容易構造或者不容易獲取的對象,用一個虛擬的對象來創建以便測試的測試方法。

舉個例子,假設一個登錄的service接口的實現邏輯爲如下:

  1. 根據用戶id獲取用戶的用戶名和密碼
  2. 如果不存在用戶,返回錯誤信息。否則繼續
  3. 將密碼加密處理
  4. 與查詢出來的密碼進行對比,返回對比結果

該實現方法如下:


private UserDao userDao;
public Boolean login(Integer uid,String pwd) {

    User u = userDao.selectUserByUid(uid);
    
    if (u == null) {
        return false;   
    }
    
    String pwdEncryStr = EncrypUtil.encry(pwd);
    
    return pwdEncryStr.equals(pwd);
}

使用Spock框架和用Groovy作爲測試語言,這裏寫其中的一個測試用例:

/**
 * 測試用例:用戶不存在
 * 測試步驟:
 *       1. mock一個userDao對象
 *       2. 調用userDao.selectUserByUid() 方法時返回 null 值
 *       3. 開始測試,看結果是否符合預期
 */      


@Autowired
LoginService loginService //待測試的類

UserDao userDao = Mock() // mock一個userDao對象

def "user not exists" () {
     given:
       userDao.userDao.selectUserByUid(*_) >> null  //這裏設定當調用 selectUserByUid 方法時返回 null
     
    expect:
        loginService.login( 1003 , "password" ) == false // 斷言,看是否返回false
}

使用mock技術對方法和對象進行模擬是很方便,但如果一個service方法中需要mock對象的數量很多時,單元測試就變得比較繁瑣,需要mock很多對象並且要設定很多返回值,導致寫單元測試的收益遠遠小於不寫的情況。有時service層的邏輯複雜時,寫測試也是無從下手。如果遇到這種情況,建議檢查一下該service接口和各個被使用的方法設計是否合理。

4.2 使用內存數據庫

寫單元測試時,數據持久層(dao層)的單元測試比其他層次要特殊一點,因爲是直接操作數據庫的。有人一開始想到的方法是使用一個本地的數據庫作爲測試數據庫,測試數據層接口時直接操作該數據庫,測試完成後將數據進行回滾。這方法看起來很不錯,但在做測試時依賴了實際的數據庫,與實際的開發環境有耦合。如果是團隊開發,因每個人的開發環境不同,數據庫也不一定存在,這樣通常導致測試失敗。

其實,在寫數據層的單元測試時,可以使用內存數據庫作爲測試數據。

內存數據庫,顧名思義就是將數據放在內存中直接操作的數據庫。相對於磁盤,內存的數據讀寫速度要高出幾個數量級,將數據保存在內存中相比從磁盤上訪問能夠極大地提高應用的性能。

內存數據庫是非常適合用於單元測試的,它不依賴實際的數據庫,測試代碼不管在哪臺機器上運行都不會受到限制,而且每一次運行都可以保證數據一致在開發時,通常使用操作數據庫的框架進行數據查詢的,一般來說,成熟的數據持久層框架都實現了用於單元測試的內存數據庫,可以查閱相關文檔進行了解。

5. 持續集成

5.1 集成測試

集成測試的概念不再這裏重複,這裏舉一個Web端項目集成測試的例子。

Web服務端的集成測試可以選擇api接口作爲測試目標,具體測試以下步驟完成:

  1. 根據需求寫測試用例
  2. 根據測試用例準備相應的測試數據
  3. 跑所有的測試腳本,將結果保存,如果有錯則通知相關人員處理
5.2 持續集成

持續集成是一種軟件開發實踐,每次集成都通過自動化的構建(包括編譯,發佈,自動化測試)來驗證,從而儘早地發現集成錯誤。這裏大概講講它的流程吧。

流程

  1. 提交

流程的第一步,是開發者向代碼倉庫提交代碼。所有後面的步驟都始於本地代碼的一次提交(commit)。

  1. 測試

代碼倉庫對commit操作配置了鉤子(hook),只要提交代碼或者合併進主幹,就會跑自動化測試(主要是單元測試)。

  1. 構建

通過第一輪測試,代碼就可以合併進主幹,就算可以交付了。交付後可以進行構建了,之後再進行測試

  1. 測試

這次測試是全面測試,主要是單元測試(如果構建前跑完了所有單元測試,這裏可以不重複跑)和集成測試,必要時可以加端對端測試。該過程主要是自動化測試,當然有一些自動化測試比較難實現的,就要人工測試。

  1. 部署

全部測試完畢並且通過之後就可以部署到服務器上

持續集成的工具有很多,比如這裏就介紹了幾種比較流行的持續集成工具:8個流行的持續集成工具,目前我項目中用的是Jenkins,使用感覺還不錯,部署方便,推薦使用。

6.總結

寫了挺多,因爲個人水平有限,所以有很多東西沒有細說,還有一些沒有選擇詳細寫,說多了顯得囉嗦。有需要自己去查找相關資料進行深入瞭解吧。

本章主要講了以下幾個點:

  • 軟件測試的分類
  • 系統的分層測試概念
  • 單元測試的一些技巧
  • 集成測試和持續集成的步驟

如果哪裏寫的不對可以留言交流交流。

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