Thinkin Markdown

讓 AI 幫你改程式之前,請先準備好測試

生產環境缺乏測試時,即使 AI 生成程式碼再完美,也難以確保系統行為不被意外破壞

發佈時間 2026-05-23
閱讀時間 6 分鐘
主題 人工智慧
標籤
軟體工程工程思維開發者成長

前言

前幾天,有位工程師正在處理弱掃工具掃出來的問題,跑來問我應該怎麼改。

他的情境其實很常見:

🔎 系統裡已經有一段生產程式碼(Production Code),現在弱掃工具指出它可能有安全風險。問題是,這段程式沒有相關測試,所以他不太確定改完之後,行為是不是仍然正確,也不確定修改前後是否等價

這種情境下,最直覺的反應可能是:「既然弱掃說有問題,那就趕快改掉吧。」

但我反而會覺得,這時候最需要小心。

因為真正的風險不只是弱掃指出的問題,而是:

我們在沒有測試保護的情況下,修改了一段正在生產環境運作的程式。

AI 可以協助分析,但不應該直接取代把關

💡 我當時給他的第一個建議是,可以先請 AI 協助評估這個問題。

例如讓 AI 幫忙看:

這個弱掃問題的本質是什麼?
它是真實風險,還是可能是誤報?
目前這段程式有哪些潛在問題?
有沒有比較小範圍、低風險的修改方式?
修改後可能會影響哪些行為?

這一步我覺得很適合交給 AI 協助。

AI 很擅長快速閱讀程式碼、解釋風險、提出幾種可能的修改方向,也可以提醒我們一些容易忽略的邊界情境。

💥 但 AI 給出的修改建議就算看起來合理,也不代表它一定符合系統原本的行為。

尤其是既有系統裡,常常有很多隱含規則:

某些看起來奇怪的行為,其實是為了相容舊資料
某些條件判斷,是為了避開歷史問題
某些輸出格式,已經被其他系統依賴
某些例外情境,只有生產環境流量才會遇到

這些東西,AI 不一定知道。

所以我會把 AI 視為一個很強的協作者,但不是最後的保證者。

真正能幫我們把關的,還是測試。

在改生產程式碼之前,先把現有行為固定下來

💡 如果一段生產程式碼沒有測試,我會傾向先補測試,再開始修改。

這裡的測試,不一定一開始就要寫得很完美,也不一定要馬上重新設計整個程式。

比較務實的做法是先寫特徵測試(Characterization Test)

特徵測試的目的不是證明舊程式設計得很好,而是先記錄:

這段程式現在的行為是什麼?
輸入 A 時,目前會輸出什麼?
遇到邊界條件時,目前怎麼處理?
哪些行為是外部已經依賴的?

也就是先把「現在的樣子」固定下來。

這麼做的好處是,當我們接著讓 AI 協助修改程式時,就有一張安全網可以確認:

原本應該保留的行為有沒有被破壞?
新修改是否只影響預期範圍?
弱掃問題是否真的被處理?
有沒有引入新的副作用?

沒有測試時,我們只能靠感覺判斷改得對不對。

有測試時,我們至少有一個可以被執行、被驗證的基準。

一個簡單的例子:從弱掃問題看 AI 協作修改

假設系統裡有一段既有程式:

public string GetUserDisplayName(string name)
{
    return $"<div>{name}</div>";
}

這段程式會把使用者名稱包在 HTML 的 div 裡。

如果弱掃工具指出這裡可能有 XSS 風險,原因是使用者輸入被直接輸出到 HTML 中。

例如:

GetUserDisplayName("<script>alert(1)</script>");

可能會產生:

<div>
    <script>
        alert(1);
    </script>
</div>

這確實是一個需要處理的問題。

這時候我們可以請 AI 協助分析,AI 很可能會建議使用 HTML Encode:

public string GetUserDisplayName(string name)
{
    return $"<div>{HttpUtility.HtmlEncode(name)}</div>";
}

這個修改方向看起來合理。

但在真正修改之前,我們應該先補上現有行為的測試。

XSS 是一種常見的安全漏洞,攻擊者可以透過注入惡意的 JavaScript 程式碼來竊取使用者資料或執行不當操作。弱掃工具會檢測到這種風險,建議開發者對輸入進行適當的處理,例如 HTML Encode 以防止惡意程式碼被執行

先補現有行為測試

例如先寫一個測試,確認原本的主要行為:

[Fact]
public void GetUserDisplayName_ShouldWrapNameWithDiv()
{
    var service = new UserService();

    var result = service.GetUserDisplayName("Neil");

    Assert.Equal("<div>Neil</div>", result);
}

這個測試看起來很簡單,但它有一個重要目的:

它先幫我們固定了目前生產程式碼的基本行為。

也就是:

輸入一個一般名稱
系統會把它包進 div
輸出格式是 <div>{name}</div>

接著,我們再補上安全相關的測試:

[Fact]
public void GetUserDisplayName_ShouldEncodeHtmlInput()
{
    var service = new UserService();

    var result = service.GetUserDisplayName("<script>alert(1)</script>");

    Assert.Equal(
        "<div>&lt;script&gt;alert(1)&lt;/script&gt;</div>",
        result
    );
}

這個測試則是在描述新的安全需求:

如果輸入包含 HTML 或 Script
輸出時應該被 Encode
不能直接原樣輸出到 HTML 裡

有了這兩種測試後,再進行修改就會安全很多。

因為我們同時確認了兩件事:

原本包 div 的行為仍然存在
新的安全需求也被滿足

AI 協作時,測試是最重要的邊界

這個例子雖然是弱掃問題,但我真正想帶出的不是「弱掃要怎麼修」。

更重要的是:

只要是透過 AI 協作修改既有程式,都應該要有測試把關。

因為 AI 產生程式碼的速度很快,也常常能提出看似合理的解法。

但越是這樣,我們越需要一個客觀機制來驗證它。

不然很容易發生這種情況:

AI 改掉了弱掃問題,但也改壞了原本行為
AI 重構了程式,但刪掉了某個隱含規則
AI 讓程式看起來更乾淨,但破壞了相容性
AI 通過了表面案例,但漏掉邊界條件

💥 這些問題不一定是 AI 不好,而是因為它缺少完整的系統脈絡。

測試的角色,就是把這些脈絡盡量明文化。

建議流程

如果要讓 AI 協助修改生產程式碼,我會建議流程大概是這樣:

1. 先請 AI 協助分析問題
2. 確認修改方向是否合理
3. 補上現有行為的特徵測試
4. 補上新需求或安全情境的測試
5. 再讓 AI 協助修改程式
6. 跑測試確認行為沒有被破壞
7. 再次檢視(Review)AI 產生的程式碼
8. 必要時補更多邊界案例

這個流程的重點不是讓開發變慢,而是讓修改變得可控。

AI 可以加速我們理解問題、撰寫測試、產生修改方案。

但測試可以幫我們確認,這些加速沒有把系統推向未知風險。

結語

AI 讓修改程式變得比以前容易很多。

但也正因為修改變容易了,我們更需要小心:容易修改,不代表容易改對。

尤其是面對生產程式碼、遺留程式碼,或任何缺乏測試保護的程式時,我們不應該只是把 AI 產生的修改直接套上去。

👍 比較好的做法是,先用測試固定現有行為,再讓 AI 協助修改,最後用測試確認結果。

AI 可以是很好的協作者。

但在軟體開發裡,真正讓我們安心前進的,仍然是可以被反覆執行的驗證機制。

也就是測試。

所以,讓 AI 幫你改程式之前,請先準備好測試

如果這篇文章對你有幫助,歡迎分享給更多人!

贊助支持

如果你喜歡我們的文章,或是這些內容對你有幫助,歡迎透過以下平台請我們喝杯咖啡,支持我們持續創作!

Ko-fi

作者

NE

Neil Tsai

樂於分享所見所聞所覺所知的全端工程師

留言功能需要 Cookie 授權

為了載入留言功能,我們需要您同意使用「功能性 Cookie」。您可以隨時在設定中調整。

免責聲明

本網站對於任何使用或引用本網站網頁資料引致之損失或損害,概不負責。本網站亦有權隨時刪除、暫停或編輯本網站所登載之各項資料,以維護本網站之權益。除法律有強制規定外,在任何情況下,本網站對於 (1) 使用或無法使用本網站之各項服務;(2) 經由本網站取得訊息或進行交易;(3) 第三人在本網站上之陳述或作為;以及 (4) 其他與本網站服務有關之事項所致生之任何直接、間接、附帶、特別、懲罰性或衍生性損害,一概不負賠償責任。

CopyRight © 2026 Thinkin Markdown