iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0
自我挑戰組

Java 程式設計與實作:30 天打造個人記帳系統系列 第 29 篇

系統測試與錯誤修正:完成記帳系統最後檢查

  • 分享至 

  • xImage
  •  

不知不覺已經來到 Day 29。

前面幾天一直在增加新的功能,現在我的 Java 個人記帳系統已經可以做到:

新增消費
查看消費紀錄
修改消費紀錄
刪除消費紀錄
計算總支出
分類支出統計
設定與檢查預算
依日期查詢
關鍵字搜尋
最高與最低支出分析
月支出統計
檔案儲存與讀取
自動儲存

功能越來越多之後,我發現「程式可以執行」並不代表「程式真的沒有問題」。

所以今天不繼續增加新功能,而是要進行一個完整程式很重要的階段:

Testing(測試)與 Debugging(除錯)。

什麼是 Testing?

Testing 就是:

實際操作程式,確認每個功能是不是按照預期執行。

以前寫比較小的程式時,可能只要執行一次:

程式可以跑
→ 完成

但是現在的記帳系統有十幾個功能,所以需要一個一個測試。

今天我先列出測試項目:

測試 1:新增消費
測試 2:查看紀錄
測試 3:修改紀錄
測試 4:刪除紀錄
測試 5:總支出
測試 6:分類統計
測試 7:預算功能
測試 8:日期查詢
測試 9:關鍵字搜尋
測試 10:最高/最低支出
測試 11:月支出統計
測試 12:檔案儲存
測試 13:重新開啟程式
測試 14:錯誤輸入

這次不是只測「正常情況」,也要故意輸入一些錯誤資料。

測試一:新增消費

先輸入:

請輸入消費項目:早餐
請輸入消費金額:60
請選擇消費分類:1

結果:

記帳成功!
日期:2026-10-02

查看紀錄:

2026-10-02|早餐|60 元|飲食

這部分正常。

測試二:新增後有沒有自動儲存?

打開:

expenses.txt

看到:

2026-10-02,早餐,60,飲食

代表 Day 23 加入的:

saveExpenses();

有正常執行。

測試三:重新啟動程式

這次直接關閉程式,再重新執行。

畫面:

記帳資料讀取成功!

選擇:

  1. 查看紀錄

結果:

  1. 2026-10-02|早餐|60 元|飲食

代表:

loadExpenses();

也有正常運作。

現在資料流程已經是:

新增資料
↓
ArrayList
↓
saveExpenses()
↓
expenses.txt
↓
關閉程式
↓
重新開啟
↓
loadExpenses()
↓
ArrayList

測試四:刪除不存在的紀錄

假設目前只有:

  1. 早餐
  2. 捷運

卻輸入:

請輸入要刪除的紀錄編號:10

程式會經過:

if (
number >= 1
&& number <= expenses.size()
)

因為:

10 <= 2

是 false。

所以顯示:

沒有這筆紀錄!

程式不會當掉。

測試五:沒有資料時執行功能

如果:

expenses.size() == 0

這時候使用:

刪除
修改
最高最低分析

都可能發生問題。

所以之前已經加入:

if (expenses.size() == 0) {
System.out.println(
"目前沒有消費紀錄。"
);
return;
}

這個 return 可以直接結束 Method。

這次測試後,我更理解為什麼之前一直要做「空資料檢查」。

測試六:月份輸入錯誤

月支出統計正常應該輸入:

1 ~ 12

故意輸入:

15

因為 Day 28 已經加入:

if (month < 1 || month > 12) {
System.out.println(
"月份必須是 1~12。"
);
return;
}

所以:

月份必須是 1~12。

測試成功。

測試七:日期格式輸入錯誤

正常:

2026-10-02

故意輸入:

2026/10/02

LocalDate.parse() 無法正常轉換。

但因為有:

try {
LocalDate searchDate =
LocalDate.parse(input);
} catch (Exception e) {
System.out.println(
"日期格式錯誤,請使用 YYYY-MM-DD。"
);
}

所以程式顯示:

日期格式錯誤,請使用 YYYY-MM-DD。

而不是直接停止。

測試八:搜尋不存在的關鍵字

輸入:

請輸入搜尋關鍵字:飛機

如果沒有資料:

找不到符合的消費紀錄。

這個功能也正常。

測試九:預算功能發現一個問題

今天測試時,我發現一個之前沒有處理好的地方。

假設:

設定預算:5000 元

程式執行期間可以正常看到:

目前預算:5000 元
目前支出:1200 元
剩餘預算:3800 元

但是關閉程式再重新開啟後:

static int budget = 0;

預算又變回:

0

原因是目前只有:

消費紀錄

有存進檔案。

預算沒有儲存。

這就是今天 Testing 發現的 Bug。

修正:把預算也存進檔案

今天新增:

budget.txt

專門保存預算。

需要使用的還是之前學過的:

File
FileWriter
Scanner

建立 saveBudget()

public static void saveBudget() {
try {
FileWriter writer =
new FileWriter(
"budget.txt"
);
writer.write(
String.valueOf(budget)
);
writer.close();
} catch (IOException e) {
System.out.println(
"預算儲存失敗!"
);
}
}

假設:

budget = 5000;

budget.txt 就會變成:

5000

String.valueOf() 是什麼?

writer.write() 比較適合寫入文字。

但是:

budget

是:

int

所以使用:

String.valueOf(budget)

把:

int 5000

轉成:

String "5000"

再寫進檔案。

設定預算後自動儲存

原本:

budget =
scanner.nextInt();

今天加:

saveBudget();

所以:

budget =
scanner.nextInt();
scanner.nextLine();
saveBudget();

現在設定預算後,也會自動儲存。

再建立 loadBudget()

重新開啟程式時,需要讀回預算:

public static void loadBudget() {
try {
File file =
new File(
"budget.txt"
);
Scanner fileScanner =
new Scanner(file);
if (fileScanner.hasNextLine()) {
budget =
Integer.parseInt(
fileScanner.nextLine()
);
}
fileScanner.close();
} catch (Exception e) {
budget = 0;
}
}

如果:

budget.txt

裡面是:

5000

透過:

Integer.parseInt()

轉回:

int 5000

最後:

budget = 5000;

啟動時讀取兩種資料

原本:

loadExpenses();

現在改成:

loadExpenses();
loadBudget();

所以:

啟動程式
↓
loadExpenses()
↓
讀取消費紀錄
↓
loadBudget()
↓
讀取預算
↓
開始操作

這樣重新啟動程式後,預算也不會消失了。

今天最後修正 setBudget()

public static void setBudget() {
System.out.println();
System.out.println(
"===== 設定預算 ====="
);
System.out.print(
"請輸入預算金額:"
);
budget =
scanner.nextInt();
scanner.nextLine();
if (budget < 0) {
System.out.println(
"預算不能小於 0!"
);
budget = 0;
return;
}
saveBudget();
System.out.println(
"預算設定成功:"
+ budget
+ " 元"
);
}

這次也順便避免:

預算 = -5000

這種不合理的輸入。

Day 29 最終新增的程式

今天不需要把前面幾百行完全重寫,主要是在 Day 28 完整版本中加入三個地方。

第一個是在 main():

public static void main(String[] args) {
loadExpenses();
loadBudget();
boolean running = true;
// 原本程式繼續...
}

第二個是修改 setBudget():

public static void setBudget() {
System.out.println();
System.out.println(
"===== 設定預算 ====="
);
try {
System.out.print(
"請輸入預算金額:"
);
int newBudget =
scanner.nextInt();
scanner.nextLine();
if (newBudget < 0) {
System.out.println(
"預算不能小於 0!"
);
return;
}
budget = newBudget;
saveBudget();
System.out.println(
"預算設定成功:"
+ budget
+ " 元"
);
} catch (InputMismatchException e) {
System.out.println(
"預算必須輸入數字!"
);
scanner.nextLine();
}
}

這裡我又做了一個小修正。

不是直接:

budget = scanner.nextInt();

而是先:

int newBudget =
scanner.nextInt();

確認它不是負數之後:

budget = newBudget;

這樣錯誤輸入就不會把原本的預算改掉。

第三個是加入:

public static void saveBudget() {
try {
FileWriter writer =
new FileWriter(
"budget.txt"
);
writer.write(
String.valueOf(budget)
);
writer.close();
} catch (IOException e) {
System.out.println(
"預算儲存失敗!"
);
}
}
public static void loadBudget() {
try {
File file =
new File(
"budget.txt"
);
Scanner fileScanner =
new Scanner(file);
if (fileScanner.hasNextLine()) {
budget =
Integer.parseInt(
fileScanner.nextLine()
);
}
fileScanner.close();
} catch (Exception e) {
budget = 0;
}
}

其他功能則沿用 Day 28 的版本。

最後做一次完整測試

我整理了一次目前系統的測試結果:

測試項目 測試結果
新增消費 ✓ 正常
查看紀錄 ✓ 正常
修改紀錄 ✓ 正常
刪除紀錄 ✓ 正常
總支出統計 ✓ 正常
分類統計 ✓ 正常
預算設定 ✓ 正常
預算重新啟動後保留 ✓ 修正完成
日期查詢 ✓ 正常
錯誤日期格式 ✓ 有提示
關鍵字搜尋 ✓ 正常
最高/最低支出 ✓ 正常
月支出統計 ✓ 正常
錯誤月份 ✓ 有提示
消費資料自動儲存 ✓ 正常
關閉後重新讀取 ✓ 正常

今天最大的收穫反而不是寫出一個新的功能,而是發現:

測試本身就是程式開發的一部分。

Testing 和 Debugging

今天也終於比較理解這兩個常看到的英文。

Testing
= 測試程式
= 找出問題

而:

Debugging
= 除錯
= 找到問題後修正

例如今天:

重新開啟程式
↓
發現預算消失
↓
Testing 找到問題
↓
檢查原因
↓
預算沒有寫進檔案
↓
加入 saveBudget()
加入 loadBudget()
↓
Debugging 完成
↓
再次測試

這就是一個很簡單的軟體測試與除錯流程。

Day 29 學習心得

今天沒有繼續增加很多新功能,而是把目前完成的記帳系統重新操作一次,測試新增、修改、刪除、查詢、統計、預算和檔案儲存等功能。

在測試過程中,我發現原本的預算只存在程式執行期間,只要重新啟動程式就會變回 0。因此今天另外使用 budget.txt 保存預算,並加入 saveBudget() 和 loadBudget(),讓預算也能像消費紀錄一樣保存下來。

這次讓我發現,程式能夠成功執行並不代表已經完全沒有問題。有些 Bug 必須真的操作不同情況才會發現。Testing 是找出問題,而 Debugging 則是找出原因並修正問題。

從 Day 1 只有幾行 System.out.println(),到現在已經有一套可以新增、修改、刪除、儲存、搜尋和分析消費資料的記帳系統。剩下最後一天,我想把這 30 天完成的內容整理起來,看看自己到底學會了哪些 Java 技術。


上一篇
月支出統計:看看一個月到底花了多少錢
下一篇
30 天 Java 挑戰完成!我的個人記帳系統最終成果
系列文
Java 程式設計與實作:30 天打造個人記帳系統 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言