單元測試實(shí)踐
本文首先講述了什么是單元測試、單元測試的價值、一個好的單元測試所具備的原則,進(jìn)而引入如何去編寫一個好的單元測試,通義靈碼是如何快速生成單元測試的。
什么是單元測試?
單元測試是一種軟件測試方法,通過編寫代碼來驗(yàn)證應(yīng)用程序中最小的可測試單元(如單個函數(shù)、方法或類)的正確性。通常,單元測試由開發(fā)人員在功能實(shí)現(xiàn)過程中或完成后編寫,其目的是確保每個最小可測試單元都能按照設(shè)計(jì)預(yù)期正常工作。
單元測試的價值
單元測試的價值主要體現(xiàn)在提高軟件質(zhì)量和可靠性,?確保代碼在修改或重構(gòu)后仍然能夠正常運(yùn)行。?單元測試的優(yōu)勢包括:
提高代碼質(zhì)量:?通過發(fā)現(xiàn)代碼中的錯誤和漏洞,?從而提高代碼的質(zhì)量和可靠性。?
提高開發(fā)效率:?在開發(fā)過程中及時發(fā)現(xiàn)問題,?減少開發(fā)周期和成本。?
便于重構(gòu)和維護(hù):?確保代碼在重構(gòu)和維護(hù)過程中不會出現(xiàn)新的錯誤和漏洞。?
有助于團(tuán)隊(duì)協(xié)作:?作為團(tuán)隊(duì)成員之間的溝通和協(xié)作工具,?提高團(tuán)隊(duì)的協(xié)作效率和質(zhì)量。?
此外,?單元測試還可以讓軟件故障盡早被發(fā)現(xiàn),?避免故障遺留到后期由于定位修復(fù)難度帶來的更大損失。?它的可回歸性為軟件提供了一層安全防護(hù)網(wǎng),?為軟件后續(xù)的重構(gòu)和修改提供了安全保障。?單元測試還為軟件單元如何被使用提供了天然的代碼樣例使用手冊。
遵循的原則
好的單元測試就像空氣(AIR)一樣感覺不到,但在測試質(zhì)量的保障上,卻是非常關(guān)鍵的。好的單元測試宏觀上來說,具有自動化(A)、獨(dú)立性(I)、可重復(fù)執(zhí)行(R)的特點(diǎn)。
A: Automatic(自動化):單元測試應(yīng)能被自動化執(zhí)行,以便在代碼更改時快速確認(rèn)新加入的代碼沒有破壞已有功能,通常情況下會將單測接入到持續(xù)集成中,每當(dāng)代碼有變更時都會通過持續(xù)集成自動觸發(fā)單元測試。
I: Independent(獨(dú)立性):每個單元測試應(yīng)當(dāng)是獨(dú)立的,不能依賴于其他測試的執(zhí)行順序或結(jié)果。這也要求單測的測試顆粒度必須足夠小,只有這樣才能滿足獨(dú)立性。
R: Repeatable(可重復(fù)執(zhí)行):好的單元測試在同樣的條件下,每次運(yùn)行應(yīng)當(dāng)給出相同的結(jié)果。它不應(yīng)依賴于外部因素(如網(wǎng)絡(luò)、數(shù)據(jù)庫或文件系統(tǒng)),需要對這些外部的依賴進(jìn)行正確的mock 。
除此之外,好的單測還必須要滿足有明確的斷言,執(zhí)行速度快,邊界測試充分,覆蓋率高等特點(diǎn)。只有滿足這些條件的單測才是好的單測,好的單元測試是對代碼質(zhì)量保障至關(guān)重要的一環(huán)。
如何編寫單元測試?
下面以Java語言為例來介紹如何編寫單元測試,總體遵循以下幾個步驟:
拆分詳細(xì)的測試用例
考慮分支條件
在編寫單元測試時,需要考慮代碼中的所有分支。分支包括if、else、switch語句等,每個分支都需要單獨(dú)測試。例如:
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。
針對每個分支,都需要編寫一個測試用例。
尋找邊界條件
除了分支,還需要考慮邊界條件。例如,對于上述分類函數(shù),邊界值是-1、0和1。邊界條件測試可以找出可能潛在的問題,確保代碼在極限條件下也能正常工作。
制定統(tǒng)一的單測規(guī)范
命名規(guī)范
單元測試類通常采用類名Test的形式。例如,如果要測試一個Calculator類,則單元測試類可以命名為CalculatorTest。單元測試方法的命名應(yīng)當(dāng)描述具體要測試的內(nèi)容。例如:
public class CalculatorTest {
@Test
public void testAddition() {
// 測試內(nèi)容
}
@Test
public void testSubtraction() {
// 測試內(nèi)容
}
}
存放路徑
一般情況下,單元測試類存放的位置在與被測試類相同包名的下面,但在不同的目錄中。在標(biāo)準(zhǔn)的 Maven 項(xiàng)目結(jié)構(gòu)中,源代碼放在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是一個強(qiáng)大的模擬框架,用于創(chuàng)建虛擬對象,簡化單元測試,特別是在測試不易創(chuàng)建的依賴對象時非常有用。
添加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()); } }
如何使用通義靈碼快速生成單測
在大多數(shù)開發(fā)者的編程習(xí)慣中,通常采用Test Later的方法進(jìn)行單元測試,即首先編寫好代碼,然后再為代碼編寫相應(yīng)的單元測試。在此背景下,利用通義靈碼生成單元測試顯得尤為便捷。以下列舉幾種使用通義靈碼生成單元測試的方式。
手工選中代碼方式生成
在 IDE 編輯區(qū)中,通過通義靈碼選中某段代碼來生成單測,選中代碼后,在靈碼的問答框內(nèi),通過 /generate unit test
來生成與選中的代碼對應(yīng)的單元測試。
使用/generate unit test
這個命令時,可以在輸入框追加更多的信息,來生成更符合開發(fā)者需要的測試用例,如需要支持JUnit5或采用Mockito進(jìn)行Mock,就可以采用 /generate unit test
JUnit5
Mockito
這樣的方式,后面兩個關(guān)鍵詞被當(dāng)作前面命令的參數(shù),這樣的使用方式,同樣適用于其他命令。
使用快捷按鈕方式生成
通義靈碼插件在每個方法簽名的上面都會有一個小圖標(biāo),單擊圖標(biāo)后會彈出相應(yīng)的命令菜單,選擇生成單元測試。
也可以選擇要生成的代碼塊,然后單擊右鍵來選擇生成單元測試功能。
采納單元測試
單測代碼生成完畢后,在問答區(qū)的代碼塊右上角,會有三個選項(xiàng),分別是插入代碼,復(fù)制和新建文件:
插入代碼:會將當(dāng)前生成的單測代碼插入到當(dāng)前打開的文件中。
復(fù)制:即復(fù)制代碼塊的代碼,由用戶自行選擇將代碼復(fù)制到哪個文件中。
新建文件:會按照J(rèn)ava單測的規(guī)范,新生成一個單測類文件,放到指定的目錄中(對應(yīng)單測方法文件所在的test目錄下),如果已經(jīng)存在同名的單測文件,需要用戶自主確認(rèn)是否覆蓋原文件。
單測生成追問
如果您對當(dāng)前生成的單測代碼不滿意(需要使用特定的單測框架或者生成更多的單測方法),只需在問答區(qū)中的輸入框輸入相應(yīng)的文本進(jìn)行追問即可,或者也可以單擊預(yù)置的單測追問Tag,如示例中追問的Tag :Retry
、Use Mockito
、Use Spring Test
和Explain code
,進(jìn)行追問,直到生成您滿意的單測代碼為止。
一般根據(jù)代碼生成的單元測試,會枚舉常用的測試用例,并不會遍歷所有的用例。如果您覺得生成的用例不足,建議先采納當(dāng)前生成的幾個用例,放到測試文件當(dāng)中。然后,切換到測試文件中,采用代碼續(xù)寫的方式,通義靈碼會幫助您續(xù)寫新的測試用例。
結(jié)語
單元測試是重要的編程實(shí)踐,為編碼過程搭建質(zhì)量圍欄。同時,采用測試驅(qū)動開發(fā)實(shí)踐中的Test First ,能夠顯著推動代碼設(shè)計(jì)的演變。通義靈碼,可以極大降低單元測試框架的搭建和測試用例編寫的工作量。同時,使用通義靈碼對單元測試用例保鮮,可以顯著提升編碼質(zhì)量。