iT邦幫忙

2024 iThome 鐵人賽

DAY 14
0
Software Development

我獨自開發 - 30天進化之路,掌握 Laravel + Nuxt系列 第 14

D14 - 完整驗證應用程式:為重構築起無憂的安全防線

  • 分享至 

  • xImage
  •  

哈囉,大家好!經過前面的努力,我們已經完成了個人財務管理系統的基本功能。但你有沒有想過,當程式碼越來越龐大、複雜時,修改一個小地方可能會引發什麼樣的連鎖反應?
在這篇文章中,我想和大家聊聊單元測試的重要性,特別是它如何為我們的程式碼提供一層安全防線,讓我們在重構時可以無後顧之憂。

一、為什麼重構需要安全防線?

在開發過程中,難免會遇到需要重構的情況。也許一開始的設計不夠完善,或者需求發生了變化。然而,隨著專案的複雜度增加,每次修改都有可能影響到其他部分。這種不確定性常常讓人感到焦慮,甚至不敢輕易動手。
還記得有一次,我在一個專案中需要優化一個看似簡單的函式。結果,一改之下,整個系統都出現了奇怪的錯誤。當時真是頭大,花了好幾個小時才找到問題所在。那次經驗讓我深刻體會到,沒有單元測試的保護,重構真的像是在走鋼索,一不小心就可能摔得很慘。

二、單元測試如何提供保護?

單元測試的目的,不僅僅是為了找到錯誤,更是為我們的程式碼建立一個可靠的基礎。透過撰寫針對各個功能的測試,我們可以:

  • 確認程式碼的正確性:確保每個模組都按照預期運作。
  • 預防回歸錯誤:修改程式碼時,立即發現是否破壞了既有功能。
  • 提高程式碼品質:促使我們寫出更模組化、可測試的程式碼。
    這樣一來,我們在進行重構時,就有了一層安全網。不用再擔心改了一行程式碼,卻導致其他地方出問題。

三、實際應用:為重構撰寫單元測試

讓我們以實際例子來看看如何利用單元測試為重構保駕護航。

1. 撰寫現有功能的測試

假設我們有一個 Transaction 模型,裡面有一個計算用戶總收入的方法:

public function calculateTotalIncome($userId)
{
    return $this->where('user_id', $userId)
                ->where('type', 'income')
                ->sum('amount');
}

在進行重構前,我們先為這個方法撰寫單元測試:

/** @test */
public function it_calculates_total_income_correctly()
{
    $user = User::factory()->create();
    Transaction::factory()->create(['user_id' => $user->id, 'type' => 'income', 'amount' => 1000]);
    Transaction::factory()->create(['user_id' => $user->id, 'type' => 'income', 'amount' => 2000]);
    Transaction::factory()->create(['user_id' => $user->id, 'type' => 'expense', 'amount' => 500]);

    $totalIncome = (new Transaction())->calculateTotalIncome($user->id);

    $this->assertEquals(3000, $totalIncome);
}

2. 進行重構

假設我們覺得這個方法應該放到 User 模型裡,更符合邏輯。因此,我們將方法移到 User 模型:

public function calculateTotalIncome()
{
    return $this->transactions()
                ->where('type', 'income')
                ->sum('amount');
}

3. 執行測試,確認功能正常

重構後,重新執行測試:

php artisan test --filter=it_calculates_total_income_correctly

如果測試通過,表示我們的重構沒有破壞原有功能。

4. 擴充測試,涵蓋更多情境

我們可以進一步撰寫更多測試,確保各種情況下功能都正常。例如,當沒有收入時:

/** @test */
public function it_returns_zero_when_no_income()
{
    $user = User::factory()->create();

    $totalIncome = $user->calculateTotalIncome();

    $this->assertEquals(0, $totalIncome);
}

四、反思:單元測試帶來的思考

透過這樣的過程,我們不僅確保了程式碼的品質,也讓自己對系統的理解更加深入。有時候,撰寫測試時會發現原本設計的不合理之處,進而促使我們思考更好的解決方案。
還有一次,我在撰寫測試時,發現某個方法的依賴太多,導致測試很難寫。這讓我意識到,這個方法需要被拆分或重構。結果,不僅測試變得容易,整個系統的結構也因此優化了。

五、結語

單元測試就像是我們程式碼的守護者,為我們築起一座安全的城牆。在這座城牆的保護下,我們可以更自在地進行重構,提升系統的品質和效能。
當然,撰寫測試需要時間和精力,但從長遠來看,這絕對是值得的投資。畢竟,誰也不想在深夜還在追著難纏的 Bug 跑。透過單元測試,我們可以更有信心地面對未來的挑戰。


上一篇
D13 - 測試不只是找到錯誤:探索單元測試的價值與具體做法
下一篇
D15 - 第二階段驗收:盤點需求,為前端整合鋪路
系列文
我獨自開發 - 30天進化之路,掌握 Laravel + Nuxt30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言