本文首先講述了什麼是單元測試、單元測試的價值、一個好的單元測試所具備的原則,進而引入如何去編寫一個好的單元測試,靈碼是如何快速產生單元測試的。
什麼是單元測試?
單元測試是一種軟體測試方法,通過編寫代碼來驗證應用程式中最小的可測試單元(如單個函數、方法或類)的正確性。通常,單元測試由開發人員在功能實現過程中或完成後編寫,其目的是確保每個最小可測試單元都能按照設計預期正常工作。
單元測試的價值
單元測試的價值主要體現在提高軟體品質和可靠性,確保代碼在修改或重構後仍然能夠正常運行。單元測試的優勢包括:
提高代碼品質:通過發現代碼中的錯誤和漏洞,從而提高代碼的品質和可靠性。
提高開發效率:在開發過程中及時發現問題,減少開發週期和成本。
便於重構和維護:確保代碼在重構和維護過程中不會出現新的錯誤和漏洞。
有助於團隊協作:作為團隊成員之間的溝通和協作工具,提高團隊的協作效率和品質。
此外,單元測試還可以讓軟體故障儘早被發現,避免故障遺留到後期由於定位修複難度帶來的更大損失。它的可迴歸性為軟體提供了一層安全防護網,為軟體後續的重構和修改提供了安全保障。單元測試還為軟體單元如何被使用提供了天然的代碼範例使用手冊。
遵循的原則
好的單元測試就像空氣(AIR)一樣感覺不到,但在測試品質的保障上,卻是非常關鍵的。好的單元測試宏觀上來說,具有自動化(A)、獨立性(I)、可重複執行(R)的特點。
A: Automatic(自動化):單元測試應能被自動化執行,以便在代碼更改時快速確認新加入的代碼沒有破壞已有功能,通常情況下會將單測接入到持續整合中,每當代碼有變更時都會通過持續整合自動觸發單元測試。
I: Independent(獨立性):每個單元測試應當是獨立的,不能依賴於其他測試的執行順序或結果。這也要求單測的測試顆粒度必須足夠小,只有這樣才能滿足獨立性。
R: Repeatable(可重複執行):好的單元測試在同樣的條件下,每次運行應當給出相同的結果。它不應依賴於外部因素(如網路、資料庫或檔案系統),需要對這些外部的依賴進行正確的mock 。
除此之外,好的單測還必須要滿足有明確的斷言,執行速度快,邊界測試充分,覆蓋率高等特點。只有滿足這些條件的單測才是好的單測,好的單元測試是對代碼品質保障至關重要的一環。
如何編寫單元測試?
下面以Java語言為例來介紹如何編寫單元測試,總體遵循以下幾個步驟:
拆分詳細的測試案例
考慮分支條件
在編寫單元測試時,需要考慮代碼中的所有分支。分支包括if、else、switch語句等,每個分支都需要單獨測試。例如:
public String classifyNumber(int number) {
if (number < 0) {
return "negative";
} else if (number == 0) {
return "zero";
} else {
return "positive";
}
}在上述代碼中,有三個分支需要測試:
number<0。
number==0。
number>0。
針對每個分支,都需要編寫一個測試案例。
尋找邊界條件
除了分支,還需要考慮邊界條件。例如,對於上述分類函數,邊界值是-1、0和1。邊界條件測試可以找出可能潛在的問題,確保代碼在極限條件下也能正常工作。
制定統一的單測規範
命名規範
單元測試類通常採用類名Test的形式。例如,如果要測試一個Calculator類,則單元測試類可以命名為CalculatorTest。單元測試方法的命名應當描述具體要測試的內容。例如:
public class CalculatorTest {
@Test
public void testAddition() {
// 測試內容
}
@Test
public void testSubtraction() {
// 測試內容
}
}存放路徑
一般情況下,單元測試類存放的位置在與被測試類別相同包名的下面,但在不同的目錄中。在標準的 Maven 專案結構中,原始碼放在src/main/java,單元測試代碼放在src/test/java。
src/main/java/com/example/Calculator.java
src/test/java/com/example/CalculatorTest.java選擇合適的單測架構
Java 常用的單元測試架構有JUnit和Mockito,下面將圍繞如何使用這兩種架構編寫基本的單元測試:
JUnit 測試架構
JUnit是Java語言中最著名的單元測試架構。它簡潔易用,提供了豐富的註解和斷言。
添加JUnit依賴(以Maven為例):
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency>編寫單元測試:
import org.junit.Test; import static org.junit.Assert.*; public class CalculatorTest { @Test public void testAddition() { Calculator calculator = new Calculator(); assertEquals(5, calculator.add(2, 3)); } }
Mockito 測試架構
Mockito是一個強大的類比架構,用於建立虛擬對象,簡化單元測試,特別是在測試不易建立的依賴對象時非常有用。
添加Mockito依賴:
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>3.11.2</version> <scope>test</scope> </dependency>編寫單元測試:
import static org.mockito.Mockito.*; import org.junit.Test; public class UserServiceTest { @Test public void testGetUser() { UserService userService = new UserService(); UserRepository mockRepo = mock(UserRepository.class); when(mockRepo.findUserById(1)).thenReturn(new User(1, "John Doe")); userService.setUserRepository(mockRepo); User user = userService.getUserById(1); assertNotNull(user); assertEquals("John Doe", user.getName()); } }
如何使用靈碼快速產生單測
在大多數開發人員的編程習慣中,通常採用Test Later的方法進行單元測試,即首先編寫好代碼,然後再為代碼編寫相應的單元測試。在此背景下,利用靈碼產生單元測試顯得尤為便捷。以下列舉幾種使用靈碼產生單元測試的方式。
手工選中代碼方式產生
在 IDE 編輯區中,通過靈碼選中某段代碼來產生單測,選中代碼後,在靈碼的問答框內,通過 /unittest來產生與選中的代碼對應的單元測試。

使用/unittest這個命令時,可以在輸入框追加更多的資訊,來產生更符合開發人員需要的測試案例,如需要支援JUnit5或採用Mockito進行Mock,就可以採用 /unittestJUnit5Mockito這樣的方式,後面兩個關鍵詞被當作前面命令的參數,這樣的使用方式,同樣適用於其他命令。
使用快捷按鈕方式產生
靈碼每個方法簽名的上面都會有一個小表徵圖,單擊表徵圖後會彈出相應的命令菜單,選擇產生單元測試。

也可以選擇要產生的程式碼塊,然後單擊右鍵來選擇產生單元測試功能。

採納單元測試
單測代碼產生完畢後,在問答區的代碼塊右上方,會有三個選項,分別是插入代碼,複製和建立檔案:
插入代碼:會將當前產生的單測代碼插入到當前開啟的檔案中。
複製:即複製代碼塊的代碼,由使用者自行選擇將代碼複製到哪個檔案中。
建立檔案:會按照Java單測的規範,新產生一個單測類檔案,放到指定的目錄中(對應單測方法檔案所在的test目錄下),如果已經存在同名的單測檔案,需要使用者自主確認是否覆蓋原檔案。

單測產生追問
如果您對當前產生的單測代碼不滿意(需要使用特定的單測架構或者產生更多的單測方法),只需在問答區中的輸入框輸入相應的文本進行追問即可,或者也可以單擊預置的單測追問Tag,如樣本中追問的Tag :Retry、Use Mockito、Use Spring Test和Explain code,進行追問,直到產生您滿意的單測代碼為止。

一般根據代碼產生的單元測試,會枚舉常用的測試案例,並不會遍曆所有的用例。如果您覺得產生的用例不足,建議先採納當前產生的幾個用例,放到測試檔案當中。然後,切換到測試檔案中,採用代碼續寫的方式,靈碼會協助您續寫新的測試案例。
結語
單元測試是重要的編程實踐,為編碼過程搭建品質圍欄。同時,採用測試驅動開發實踐中的Test First ,能夠顯著推動代碼設計的演變。靈碼,可以極大降低單元測試架構的搭建和測試案例編寫的工作量。同時,使用靈碼對單元測試用例保鮮,可以顯著提升編碼品質。