軟件測試技術之單元測試—工程師 Style 的測試方法(3)

如何設計單元測試?

單元測試設計方法

單元測試用例,和普通測試用例的設計,沒有太多不同,常見的就是等價類劃分、邊界值分析等。而測試用例的設計其實也是開發者應該掌握的基本技能。

等價類劃分

把所有輸入劃分為若干分類,從每個分類中選取少數有代表性的數據做為測試用例。

例如,一個方法計算輸入參數的絕對值的倒數,如果是輸入是 0,則拋異常。那么對這個方法寫測試的話,就應該有三個等價類,輸入是負數、0 以及正數。所以我可以選取一個負數、一個正數以及 0 來設計三個測試用例。

再舉個例子,某個方法是根據醫生的認證狀態,發送不同的消息。那么等價類可能有三種,未認證、普通認證但無權威認證、普通認證且權威認證,某些情況下可能還會包括無普通認證但有威認證。

邊界值分析

邊界值是指劃分等價類后,在邊界附近的一些輸入數據,這些輸入往往是最容易出錯的。

例如,對于上面計算絕對值的倒數的例子,那么邊界值就包括 Integer.min、-1、0、1、Integer.max 等。再舉個例子,文本框輸入范圍為 1 - 255 個字符,那么等價類按輸入長度劃分有三類 0、1 到 255、大于 255,而邊界值則包括 0、1、2、254、255、256 等。

其他類似于空數組、數組的第一個和最后一個、報表的第一行和最后一行等等,也是屬于邊界值,需要特別關注。

其他方法

除了上面提到的幾種,測試設計方法還有幾種常用的:

場景法。場景法是根據模塊實際使用的場景,例如 API 的實際調用方法、系統的實際需求場景和處理邏輯創建的用例。這種方法比較直觀,并且用例貼近實際需求的,不可忽視。

錯誤推測。錯誤推測其實就是憑直覺,考慮最容易出錯的情況來設計用例。例如,我們直到新用戶、重復請求、并發、弱網、大數據量等情況都是非常容易出錯的,那么可以針對性的設計用例。錯誤推測需要測試設計者比較熟悉業務邏輯,并且經驗豐富。

其他還有因果圖、正交法等方法,這里就不說了。

覆蓋率

如果按照前面的用例設計方法,可能會設計出很多用例。我們不可能也沒有必要把每一個用例都寫成單元測試。

怎么確認用例是否足夠呢?一個很重要的參考指標就是代碼覆蓋率。

覆蓋率指標

常用的覆蓋率指標有四種:

語句覆蓋:每條語句至少執行一次。

分支覆蓋:每個分支至少有一次為真、一次為假。

條件覆蓋:每個分支的每個條件至少有一次為真、一次為假。

路徑覆蓋:對所有的分支、循環等可能的路徑,至少都要覆蓋一次。

我們以這個簡單的代碼為例,看看這四種覆蓋率到底是什么意思。

if (a && b) {

// X

}

// Y

if (c || d) {

// X

}

語句覆蓋。只需要一個測試用例,讓 a && b 和 c || d 都為真,系統會依次執行 X、Y、Z 三個的代碼段,就能做到語句覆蓋。

分支覆蓋。至少需要兩個測試用例,讓 a && b 和 c || d 都各為真假,例如用例1 a && b 為真和 c || d 為假,用例2 則反過來,既可讓兩個條件分支都各為真一次,為假一次。

條件覆蓋。至少需要四個測試用例,條件 a 和 b 的四種組合都要執行一次,條件 c 和 d 的四種組合也都要執行一次。

路徑覆蓋。至少需要八個測試用例,條件 a、b、c 和 d 的所有組合都要執行一次。

可以看到,要做到條件覆蓋甚至路徑覆蓋,會需要非常多的測試用例。一般情況,對于復雜的邏輯,單元測試做到分支覆蓋就不錯了,必要的話再做更多完全的覆蓋。

Jacoco 覆蓋

Jacoco 的覆蓋率略有不同,這里簡單說一下。

指令覆蓋(Instructions),覆蓋所有的 Java 代碼指令。

分支覆蓋(Branches),和上面的分支覆蓋基本是一樣的。

圈復雜度覆蓋(Cyclomatic Complexity),可以認為就是路徑覆蓋率。

語句覆蓋(Lines),和上面的語句覆蓋基本是一樣的。

方法覆蓋(Methods),覆蓋所有的方法。

類覆蓋(Classes),覆蓋所有的類。

怎么寫有效的單元測試?

到現在,相信大家對怎么寫單元測試應該有一定概念了。但是很多人也會有疑問:

單元測試耗費太多時間,會不會降低生產效率?

單元測試會不會很難維護?比如修改代碼時還總是需要修改單元測試。

關于第一個問題,相信大家應該都能理解,如果我們在開發時發現 BUG,那么解決它是很容易的;但是一旦到了集成、驗收甚至上線之后,那么要解決它就要花費比較大的代價了。業界很早就有共識,并且有不少數據可以證明,有效的單元測試雖然要花費更多編碼時間,但是可以很大的減少項目的集成、測試和維護成本。

注意上面提到很重要一點是,單元測試必須是有效的,如果我們發現單元測試很難維護,那往往是因為我們沒有寫出有效的單元測試。

不是所有的代碼都需要單元測試

寫單元測試我們也需要考慮投入產出比,例如下面這些情況,寫單元測試的投入產出比可能會較差。

短期的或者一次性的項目,例如 Demo、數據更新腳本。

業務簡單的,不含太多邏輯的模塊。例如獲取或者查找一個數據,或者沒有分支條件的業務邏輯等。

UI 層,相對而言比較難做單元測試,除非 UI 本身就有比較復雜的邏輯(其實某些 UI 框架也提供了單元測試工具)。

那么那些情況下要寫單元測試呢?簡單來說,就是兩類。

邏輯復雜、不容易理解、容易出錯的模塊。例如,計算閏年的方法、訂單下單等。

公共模塊或者核心的業務模塊。

即使對于需要寫單元測試的模塊,我們也應該關注最核心最重要的測試用例,而沒必要單純的追求覆蓋率,或者追求條件覆蓋甚至路徑覆蓋,一般做到分支覆蓋就可以了。另外一個有效的方法是,對于出現的每一個 BUG,添加一個單元測試。

單元測試應該是穩定的

這里穩定的第一個含義是,單元測試不應該經常需要修改。如果單元測試經常因為底層實現邏輯的變動而需要修改,那一定不是好的單元測試。也就是說,被測單元的接口應該是穩定的、設計良好的、易于擴展的。

穩定的第二個含義是,單元測試的結果應該是穩定的。如果在不同的環境、不同的情況運行單元測試,會返回不同的結果,那就不是好的單元測試。如果測試需要依賴特定的數據、文件等,那需要有前置的初始化腳本確保依賴的數據、文件在所有環境都存在并且是一致的。

單元測試應該是灰盒測試

單元測試應該覆蓋核心邏輯的各種分支、邊界及異常,但是避免涉及易變的實現邏輯。也就是說,我們不應該把單元測試當成完全的白盒測試,但也不是黑盒測試,而應該把它當成介于白盒和黑盒之間的灰盒測試。

被測代碼應該是抽象良好的

如果我們發現一段代碼很難編寫單元測試,常常是因為這段代碼沒有符合良好的抽象規范,比如沒有使用 DI、不符合單一職責原則、或者依賴了全局的公共變量和方法等等。我們可以考慮優化這段代碼,再來嘗試單元單元測試。

談談到底什么是抽象,以及軟件設計的抽象原則 介紹了軟件抽象的原則,這里就不再重復了。

編碼時就應該同時寫好單元測試

這樣我們才能在調試時就發揮單元測試的優勢,對代碼的任何修改都能得到即時反饋。如果是后面再補充單元測試,一方面對實現可能已經不太熟悉了,編寫測試的代價更大了;另一方面,單元測試能發揮的作用也變小了。不過即使這樣,對那些需要長遠維護的項目,編寫單元測試也還是很有用的。

單元測試的代碼質量也很重要

單元測試也是代碼,也是需要不斷維護的。所以我們不應該隨隨便便的去寫單元測試,而是要把他們也當成普通代碼一樣,要做到高質量、模塊化、可維護。

為什么要寫單元測試之終極原因

終極原因是,作為一名優秀的工程師,如果被 QA 和產品經理 Challenge 有 BUG,能忍嗎?而我們工程師當然要用工程師 Style 的測試方法,那就是自動化的單元測試了,不是嗎?

文章來源:網絡 版權歸原作者所有

上文內容不用于商業目的,如涉及知識產權問題,請權利人聯系小編,我們將立即處理

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/40197.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/40197.shtml
英文地址,請注明出處:http://en.pswp.cn/news/40197.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

[UE4][C++]使用qrencode動態生成二維碼

一、使用CMake編譯x64版本qrencode 下載地址 GitHub - fukuchi/libqrencode: A fast and compact QR Code encoding libraryA fast and compact QR Code encoding library. Contribute to fukuchi/libqrencode development by creating an account on GitHub.https://github.…

2023/08/13_______JVM(CG)垃圾回收 算法(復制算法,標記清除,標記清除壓縮)

JVM GC算法 復制算法 1,每一次GC都會將伊甸(Eden)活的對象移到幸存區中:一旦Eden區被GC后 就會是空 只要有內容就是from區 誰空誰是to區 內存會從 伊甸->幸存區to->幸存from(這個時候to和from交換區域&#xf…

EXPLAIN使用分析

系列文章目錄 文章目錄 系列文章目錄一、type說明二、MySQL中使用Show Profile1.查看當前profiling配置2.在會話級別修改profiling配置3.查看profile記錄4.要深入查看某條查詢執行時間的分布 一、type說明 我們只需要注意一個最重要的type 的信息很明顯的提現是否用到索引&…

kafka線上問題優化

如何防止消息丟失 生產者: 使用同步發送把ack設成1或者all(非0,0可能會出現消息丟失的情況),并且設置同步的分區數>2 消費者:把自動提交改成手動提交 如何防止重復消費 在防止消息丟失的方案中&#…

leetcode 力扣刷題 數組交集(數組、set、map都可實現哈希表)

數組交集 349. 兩個數組的交集排序+雙指針數組實現哈希表unordered_setunordered_map 350. 兩個數組的交集Ⅱ排序 雙指針數組實現哈希表unordered_map 349. 兩個數組的交集 題目鏈接:349. 兩個數組的交集 題目內容如下,理解題意&#xff1a…

梯度爆炸和梯度消失的原因以及解決方法

文章目錄 1、原因:2、解決方法 1、原因: 梯度消失和梯度爆炸的根本原因是因為在反向傳播過程中,使用鏈式法則計算時,累積相乘效應導致梯度過大或者過小主要原因有: 1)激活函數:例如sigmoid或者…

聊聊火車的發展

目錄 1.火車的概念 2.火車的發展歷史 3.火車對戰爭的影響 4.火車對人們出行造成的影響 1.火車的概念 火車是一種由機械動力驅動的陸上交通工具,通常用來運輸人員和貨物。它由一列或多列的連接在一起的車廂組成,有軌道作為其行駛的基礎,并通…

重建與突破,探討全鏈游戲的現在與未來

全鏈游戲(On-Chain Game)是指將游戲內資產通過虛擬貨幣或 NFT 形式記錄上鏈的游戲類型。除此以外,游戲的狀態存儲、計算與執行等皆被部署在鏈上,目的是為用戶打造沉浸式、全方位的游戲體驗,超越傳統游戲玩家被動控制的…

mysql面試

基礎篇 通用語法及分類 DDL: 數據定義語言,用來定義數據庫對象(數據庫、表、字段)DML: 數據操作語言,用來對數據庫表中的數據進行增刪改DQL: 數據查詢語言,用來查詢數據庫中表的記錄DCL: 數據控制語言,用…

php正則替換文章的圖片

要使用正則表達式替換文章中的圖片鏈接,可以按照以下步驟進行操作: 1. 獲取文章內容:首先,你需要獲取包含圖片鏈接的文章內容。你可以從文件中讀取文章,或者從數據庫中檢索文章內容。 2. 使用正則表達式匹配圖片鏈接…

JAVA編程學習筆記

常用代碼、特定函數、復雜概念、特定功能……在學習編程的過程中你會記錄下哪些內容?快來分享你的筆記,一起切磋進步吧! 一、常用代碼 在java編程中常用需要儲備的就是工具類。包括封裝的時間工具類。http工具類,加解密工具類&am…

day17 | 110.平衡二叉樹、257. 二叉樹的所有路徑、404.左葉子之和

目錄: 解題及思路學習 110.平衡二叉樹 https://leetcode.cn/problems/balanced-binary-tree/ 給定一個二叉樹,判斷它是否是高度平衡的二叉樹。 本題中,一棵高度平衡二叉樹定義為: 一個二叉樹每個節點 的左右兩個子樹的高度差…

Linux學習之firewallD

systemctl status firewalld.service查看一下firewalld服務的狀態,發現狀態是inactive (dead)。 systemctl start firewalld.service啟動firewalld,systemctl status firewalld.service查看一下firewalld服務的狀態,發現狀態是active (runni…

okcc呼叫系統導入呼叫名單/客戶資料的數量上限,okcc通話聲音小有哪幾種處理辦法?

系統導入呼叫名單/客戶資料的數量上限 呼叫名單一次最多十萬 客戶資料一次最多五萬 通話聲音小有哪幾種處理辦法? 1、IP話機:通過話機上的音量調節按鈕來進行調節。 2、模擬話機:修改語音網關上的增益來實現。 “ 往IP增益”表示電話呼入…

stable diffusion 運行時報錯: returned non-zero exit status 1.

運行sh run.sh安裝stable diffusion時報錯:ImportError: cannot import name builder from google.protobuf.internal (stable-diffusion-webui/venv/lib/python3.8/site-packages/google/protobuf/internal/__init__.py) 原因:python版本過低&#xff0…

ubuntu16.04制作本地apt源離線安裝

一、首先在有外網的服務器安裝需要安裝的軟件,打包deb軟件。 cd /var/cache/apt zip -r archives.zip archives sz archives.zip 二、在無外網服務器上傳deb包,并配置apt源。 1、上傳deb包安裝lrzsz、unzip 用ftp軟件連接無外網服務器協議選擇sftp…

股票交易c接口包含哪些調用函數?

股票交易的C接口中可能包含多個調用函數,具體的調用函數取決于所使用的接口規范和交易所的要求。接下來看看下面是一些可能常見的股票交易C接口調用函數的示例: 1. 連接函數(Connect):用于與交易所建立網絡連接。 2.…

CSS(JavaEE初階系列14)

目錄 前言: 1.CSS是什么 1.1CSS基本語法 2.引入樣式 2.1內部樣式表 2.2行內樣式表 2.3外部樣式 3.選擇器 3.1選擇器的種類 3.1.1基礎選擇器 3.1.2復合選擇器 4.常用元素屬性 4.1字體屬性 4.2文本屬性 4.3背景屬性 4.4圓角矩形 4.5元素的顯示模式 4…

?LeetCode解法匯總2682. 找出轉圈游戲輸家

目錄鏈接: 力扣編程題-解法匯總_分享記錄-CSDN博客 GitHub同步刷題項目: https://github.com/September26/java-algorithms 原題鏈接: 力扣(LeetCode)官網 - 全球極客摯愛的技術成長平臺 描述: n 個朋友…

【Leetcode】84.柱狀圖中最大的矩形(Hard)

一、題目 1、題目描述 給定 n n n 個非負整數,用來表示柱狀圖中各個柱子的高度。每個柱子彼此相鄰,且寬度為 1 。 求在該柱狀圖中,能夠勾勒出來的矩形的最大面積。 示例1: 輸入:heights = [2,1,5,6,2,3] 輸出:10 解釋:最大的矩形為圖中紅色區域,面積為 10示例2:…