iT邦幫忙

2024 iThome 鐵人賽

DAY 18
0
Modern Web

與 AI 一起開發 Side Project 吧!系列 第 18

Day18 — 穩如泰山 | 極速產單元測試,如何辦到?

  • 分享至 

  • xImage
  •  

雖然上次已經自己找問題,修改完善了。但如果不搞清楚 AI 會寫錯的原因,那麽接下來請 AI 產出的測試,一樣還是可能有問題,AI 還幫我「幻想了」應該存在的組件,直接用於測試中。

所以 AI 產測試的癥結點在哪?

比較可能的原因,是 AI 模型的訓練資料集,是來自開發團隊收集而來的大數據,也就是大家寫好的程式碼來訓練,所以如果 AI 會以此做「推論」,推論說指令沒提到的部分,應該也會跟大家一樣的作法。

於是乎,AI 擅自為你「腦補」了測試的其他部分。

AI 幻想症

修正幻想

到底 AI 是幻想了什麼呢?

以下是某次使用 AI 生成的測試項目,其中一部分的測試程式碼。AI 覺得我的程式碼中「應該」要有一個 role 是 backspaceButton 的按鈕,來做到「退後」(也就是大家所熟知的往前刪除一格),但…實際上根本沒有這個組件。所以測試跑到此處時,就發生了「找不到該 role 」組件的錯誤。

//...
const backspaceButton = screen.getByRole('backspaceButton');
fireEvent.click(backspaceButton);

那該怎麼辦呢? 其實也沒什麼,大概有 2 種選擇,向 AI 妥協或是自己另起爐灶:

  1. 照 AI 給的「建議」,我們回頭改組件
  2. 不理會 AI 給的建議,參考其測試條件,我們重寫一個

我自己是選 1,既然 AI 都給我建議了,看了也沒什麼問題,那我就回頭補上,補完修改之後大概長這樣,把 role 給加在按鈕組件上

<Button onClick={handleBackspace} role="backspaceButton">
//...
</Button>

再跑一下測試,嗯,通過了,那就先這樣吧。畢竟這部分先不追求「完美」,只求可以快速生成有效且可靠的測試就行,寫法的優化可以等重構之後,到時候說不定會有新的想法,屆時再說。

要測試實作細節嗎?

可以看到說,我們測試都是以「整體」使用者會操作的行為來測試,而不是測「單一組件」的預期行為。

你可能會想說,啊這樣不就有些狀況沒測到? 比方說 handleOK 這個組件內其中一個方法。

const handleOk = () => {
    const amount = parseFloat(currentAmount);
    if (!isNaN(amount)) {
        if (isEditingAmount) {
            setPendingAmount(amount);
            setIsEditingAmount(false);
            setShowCategorySelector(true);
        } else {
            setPendingAmount(amount);
            setShowCategorySelector(true);
        }
    }
    setCurrentAmount("0");
};

有一個 if (2 種可能),嵌套內又有一個 if(2 種可能),總共會有 3 種可能(因為外層的 if 沒有 else),如下表所示意

isNaN(amount) / false isNaN(amount) / true
isEditingAmount / true 1 3
isEditingAmount / false 2 3

如果是針對這個方法做測試,「合格」的測試就要測到以上 3 種情境,都有做到個別測試。

但不這麼做,為什麼?因為這不是程式的主要邏輯,只是「實作細節」而已,哪天重構掉這部分的程式碼,測試就完全沒用了!

測以上這部分的程式沒什麼意義,目前的 Side Project 更適合「由上而下」來做測試。

由上而下產測試

先前由 AI 生成的測試,也都是「由上而下」做測試的方法,「上」是指最大的範圍,是整個 App 行為層級的大範圍。測了使用者會操作的行為,並測試預期該出現的結果。

而選擇這種「由上而下」的測試寫法,是我們「極速產測試」的前提條件。希望可以快速且可靠,而且「重構之後還不必改寫」,那麽就得從需求面著手,不以程式細節來寫測試。這樣說或許有點抽象,拿上次提到 AI 沒有幫我們寫到的測試來試試。

首先是比較簡單的,我想要知道「新增多筆帳目」,是不是真的會出現在畫面上? 給了 AI 指令:

幫我新增一個測試,用來測試多筆帳目金額會如預期渲染。

AI 馬上為我生成了測試,測試項目是測了 3 筆記帳金額都有如期記帳。

it('renders multiple account amounts correctly', () => {
  render(<App />);

  // Add first amount
  fireEvent.click(screen.getByText('1'));
  fireEvent.click(screen.getByText('0'));
  fireEvent.click(screen.getByText('OK'));
  fireEvent.click(screen.getByText('飲食'));

  // Add second amount
  fireEvent.click(screen.getByText('2'));
  fireEvent.click(screen.getByText('0'));
  fireEvent.click(screen.getByText('OK'));
  fireEvent.click(screen.getByText('日用品'));

  // Check if both amounts are rendered
  expect(screen.getByText('$10')).toBeInTheDocument();
  expect(screen.getByText('$20')).toBeInTheDocument();

  // Check if the total amount is correct
  expect(screen.getByText('$30')).toBeInTheDocument();
});

跑了一下測試,發現測試沒通過… 🤔 原來又是之前遇到的問題,沒有在選完種類之後,再次按下 OK。一樣請 AI 修正一下就行了,沒什麼大問題。

另外一個是「雙擊編輯」帳目金額,選了 claude-3.5 模型並輸入以下指令:

參考 @AccountingApp.tsx 
幫我新增一個測試,用來測試「雙擊」以編輯帳目金額。
首先是輸入 $10 娛樂的帳目,接著編輯成 $20 飲食

一樣也是咻咻咻很快就產出測試了,雖然看起來蠻有搞頭的,但看到驗測的 getByText() 寫法…嗯,應該不太對,果真如此!

https://ithelp.ithome.com.tw/upload/images/20240928/20168308CIjQGKYAUW.png

AI 又忘記我的 App 裡面會有「2 個」金額的顯示,同樣的這部分再微調一下應該就行了。另外看了一下流程,編輯那邊沒有「歸零」,所以金額會不對。

看了一下測試,應該要是沒問題才對了,為什麼又錯了呢 🤔…

既然測試沒問題,那回頭檢查一下程式邏輯,不是測試就是程式,反正也就這兩種可能而已。這才發現原來編輯那塊寫錯了 😅,在每次帳目編輯之後,都會再次把「當下輸入的金額」再次加總進 total 值。

const handleSelectCategory = (category: string) => {
    if (pendingAmount !== null) {
        //...
        setTotal(history.reduce((sum, item) => sum + item.amount, 0) + pendingAmount);
        setPendingAmount(null);
    }
    setShowCategorySelector(false);
};

那這樣的話,最快速的作法,是把 total 的值放到 useEffect 裡面做計算。於是輸入以下指令,請 AI 幫忙修改:

total 值改為 history 有變化(useEffect)時才去做加總計算

稍後了一會兒,AI 如期幫我修改完成,再次跑了測試,測試如期通過。

https://ithelp.ithome.com.tw/upload/images/20240928/20168308R0TgmIUUdC.jpg

CompletedGif

呼…,只是加 2 個測試,比想像中還要累,但有把測試寫好就是開心,今天就先寫到這邊囉~ 🥳

尾聲

指令的精準度可靠嗎?

首先是指令的精準度,我只跟 AI 說「參考 OOXX 這個檔案的程式碼,請幫我生成測試」,AI 就咻咻咻地產生一拖拉庫的測項。

可能是因為此 Project 的主題比較常見,AI 算是猜得滿準的,所以測試項目「有猜到」我想要測的,可以說是生成的精準度頗高,比預期還要好。

其次是「組件行為」的精準度,這部分精準度還好,行為模式和流程有「猜出來」,但使用的方法與驗證項目,這些「細節」則有失精準。

這有點像是:AI 寫了一個乍看頗有道理,但細看根本是在胡說八道的句子。(有用過 AI 的讀者,應該是心有戚戚焉)

在程式碼亦是如此,需要肉眼一行行檢查,檢核 AI 給的程式碼到底寫了什麼,寫法與相應的測試項目,到底「有沒有測到」該測的東西。(有可能 AI 生成的測試項目只是剛好矇對,而沒有測到實際該測的商業邏輯)

但還是挺香的

總結一下,那這樣說來,AI 提供的測試不是很準確,那我們該用嗎?

我的答案還是「用!」,不用動腦就可以秒產測項,只需要檢查與修改,這樣還是比從零開始寫要輕鬆許多呢。


上一篇
Day17 — 穩如泰山 | 測試現在才寫,來得及嗎?
下一篇
Day19 — 穩如泰山 | 測試也是需要整理維護的,跟 AI 一起整理測試
系列文
與 AI 一起開發 Side Project 吧!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言