iT邦幫忙

2023 iThome 鐵人賽

DAY 4
0

可以獲得什麼?

單元測試的使用場景,以及如何運用單元測試在開發中。


單元測試是什麼?

單元測試(Unit Testing)是軟體測試的一個階段,它專注於測試軟體中的個別單元或獨立的程式碼模組(軟體設計的最小單位),例如函數、方法、類別或組件。單元測試的目標是驗證這些單元是否按照預期工作,並且它們的行為是否符合設計和需求

使用單元測試可以獲得這幾個優點:

  • 確保功能正常:確保每個單元按照預期進行工作。這有助於確保程式碼的每個部分都執行正確,並且能夠按照設計目標運作。
  • 早期發現問題:單元測試通常在程式碼開發的早期階段實施,像是 TDD (Test-Driven Development) 測試驅動開發者會在開發前期就導入單元測試,讓開發作業進行的同時也一併檢測,因此當程式開發完畢測試也一併通過。這有助於及早發現並解決潛在的錯誤和缺陷。因為問題在開發初期就得到解決,所以大大降低後期維護的成本。
  • 支援重構:單元測試是在進行重構(重寫或優化程式碼結構)時的有力工具。它們確保重構後的程式碼仍然具有相同的功能,並且不會破壞現有的功能。
  • 持續集成:單元測試是持續整合(Continuous Integration,CI)和持續交付(Continuous Delivery,CD)流程的一部分。它們確保每次程式碼更改都不會對系統的穩定性和功能造成損害。
  • 提高可讀性和可維護性:單元測試通常包括測試案例,它們充當程式碼的文檔,幫助其他開發人員了解程式碼的預期行為。這有助於提高程式碼的可讀性和可維護性。
  • 鼓勵模組化和良好設計:撰寫單元測試通常要求程式碼模組化,有助於實現良好的程式碼設計原則,例如單一責任原則(Single Responsibility Principle)和依賴反轉原則(Dependency Inversion Principle)。

由此可知單元測試是一種強大的工具,它確保程式碼的各個部分(單元)正確運作,提早發現問題,並提高程式碼的品質、可維護性和穩定性。它是現代軟體開發實踐中的不可或缺的一部分,有助於建立可靠和高品質的軟體。

單元測試的特點

藉由上面的敘述可以得知,要實現單元測試需要幾個特性,首先是把程式切割成最小測試單位(單元),然後針對每個單元進行測試,因此單元測試擁有以下的特點:

  • 獨立性:單元測試應該是獨立的,這意味著它們不應該依賴於其他單元的結果。測試一個單元時,其他相關的模組或資源應該模擬或模擬假的,以確保測試的獨立性。
  • 自動化:單元測試通常是自動化的,這意味著它們由測試框架或工具自動執行。這有助於快速且可靠地執行測試,並在程式碼變更後輕鬆驗證功能是否正常。
  • 快速執行:每個單元測試應該能夠在很短的時間內執行,通常在幾秒或更短的時間內完成。這使得開發人員可以頻繁地運行測試,以確保程式碼的正確性與穩定性。
  • 發現錯誤: 單元測試的主要目的是發現和確認單元中的錯誤和缺陷。當發現問題時,開發人員應該修復它們,並確保測試通過。

如何實作單元測試?

之前有寫參加鐵人賽中關於 unit test 的部分,儘管部分內容仍缺,但有興趣可以參考一下:【Unit Test】Unit Test with C#

在撰寫單元測試時,可以把 TDD(測試驅動開發)概念放在開發中。。這意味著在開發過程中,同時考慮測試的角度。以測試人員和API使用者的角度思考:如果我是測試人員,我要怎麼測試這段程式碼?如果我是呼叫這 API 的人,我會怎麼進行呼叫以及提供哪些參數。這種測試思維的整合,可以在開發過程中引導我們更注意細節,例如確保數值型變數不被誤用為文字,日期格式不會變成算式。

在實作單元測試時,首先需考慮我們想要測試的內容,並根據內容來確定每個單元的範圍,確保範圍不要過大。一旦我們確定了測試的內容和被測試的範圍,就可以開始進行開發和編寫單元測試。

這時我們在撰寫單元測試時,會需要三個步驟:Arrange(安排)、Act(執行)、Assert(斷言),也就是先建立測試目標、執行功能,最後驗證結果(可參考:〈【Day 6】解說第一個Unit Test之2-測試程式碼結構與精神〉)。當程式碼完成時,使用測試運行器執行這隻 Unit Testing,就可以知道自己的程式是否正確了。以 Python 來說,最常見的是使用 unittest 來進行撰寫,由於是內建的,無需另外安裝;而 C# 則是可以用 NUnitxUnit進行撰寫。

完成程式碼後,使用測試運行器執行這些單元測試,以確保程式碼的正確性。在 Python 中,最常見的是使用 unittest 框架,它是 Python 內建的,無需額外安裝。而在 C# 中,可以選擇使用 NUnit xUnit 等框架來撰寫單元測試。

使用的場景

範例

  1. 解析股票電文

情境

當接收到股票交易的電文時,需要將其解析以提取交易相關的資訊,從中取得購買的股票與金額等等交易資料,然後把這些資料寫入資料庫儲存。

作法

這邊可以拆分成兩個主要的單元:一是解析電文並擷取關鍵資訊,二是將這些資料寫入資料庫。這邊就以前者為例。當取得電文後會解析文字,把資料存放在一個字典中,這樣就取得關鍵資訊了,我們在單元測試中,我們可以提供一個特定的電文,然後檢查此功能是否成功擷取所需的關鍵資訊,像是股票代號和購買金額、張數等等。如果沒有提供正確答案,就是測試不通過,這時測試框架將報告錯誤,我們就能立即修改這個錯誤。

  1. 持續整合(CI)

情境

當有一筆合併請求(merge request),需要檢查這個程式碼是否有問題,這次的變動是否會影響其他功能。

作法

當我們開發完程式,會藉由 Git 把這次修改的程式碼合併(merge)到主要分支(main branch)中。由於這個合併可能會影響其他人的工作,當把錯誤的程式碼推上去(Push),別人抓下來的程式碼也是錯誤的,我們在推送(push)程式碼之前,可以執行事先編寫的單元測試,以確保程式碼的品質。只有當所有這些單元測試都通過時,我們才能夠合併這次的變更。當單元測試不通過,表示此次更動影響其他功能,造成程式的不穩定,此時就不會允許本次合併需求,以維持主分支的完整性。


後記

原本以為簡簡單單的單元測試一下子就寫完,但仍洋洋灑灑一堆。因為...這是切身之痛呀...不過有了單元測試,我們程式碼的可靠度提高,也對自己的程式更有把握!深深覺得這是開發者必備的技能。

提醒:這測試階段分類不是絕對的喔!會因為各團隊狀況有所不同。


參考資料


上一篇
【D3】測試的目標是什麼?為什麼要測試?
下一篇
【D5】測試階段介紹:整合測試
系列文
精實30天:QA 概念養成計劃31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言