概述#

測試是軟體工程師的重要工作,即使你不是 Tester,面試中仍可能出現測試題。如果你應徵的是 SET(Software Engineer in Test)職位,更是必考範圍。

測試題通常分為四類:

  1. 測試一個真實世界的物件(如迴紋針)
  2. 測試一個軟體
  3. 為一個函式撰寫測試程式碼
  4. 除錯與問題排查

四種類型都要求你不預設輸入或使用者會配合。預期會有濫用的情況,並為此做好計畫。


面試官的評估重點#

表面上,測試題只是要你列出測試案例,但面試官其實在評估更多面向:

  • Big Picture Understanding(全局理解):你是否了解軟體的核心價值?能否優先處理最重要的測試?例如測試電商系統時,付款流程的正確性遠比商品圖片位置更關鍵。
  • Knowing How the Pieces Fit Together(系統整合理解):你是否了解軟體如何融入更大的生態系?測試 Google Spreadsheets 時,不只要測試基本功能,還需測試與 Gmail、外掛程式的整合。
  • Organization(組織能力):你是否有結構化地思考問題?好的應試者會先將問題拆解成類別(例如:拍照、影像管理、設定),再逐一產出測試案例,而非漫無目的地羅列。
  • Practicality(實用性):你提出的測試計畫是否實際可行?讓用戶重新安裝軟體不是個好的 bug 排查建議。

測試真實世界的物件#

範例:如何測試迴紋針?

Step 1:誰會使用它?為什麼?#

先與面試官討論使用者和使用目的。答案可能是「老師用來夾報告」,也可能是「藝術家用來彎折成形狀」,甚至兩者都是。這個答案會影響後續所有測試方向。

Step 2:使用情境有哪些?#

列出使用情境。迴紋針的主要情境可能是:在不損傷紙張的前提下夾住多張紙。

Step 3:使用範圍的邊界為何?#

定義使用邊界,例如:

  • 單次使用可夾住 30 張紙且不造成永久變形
  • 在攝氏 -10 到 50 度的環境中正常使用

Step 4:壓力/失效條件為何?#

沒有任何產品是萬能的。要分析:

  • 什麼時候可以接受失效?
  • 什麼程度的失效是可接受的?

例如洗衣機的測試:30 件衣物以下正常運作;30-45 件可能有輕微洗滌不均;45 件以上可能完全失效,但失效應該是「洗不乾淨」而非「淹水」。

Step 5:如何進行測試?#

某些測試需要創意。例如測試椅子能否承受五年正常使用,無法真的等五年,需要:

  • 定義「正常使用」(每天坐幾次?體重範圍?)
  • 用機器模擬大量使用

測試軟體#

軟體測試與真實世界物件的測試類似,但更強調測試執行的細節。

核心區別:

  • Manual vs. Automated Testing(人工 vs. 自動化測試):某些功能過於主觀(例如內容是否適當)只能人工測試;人工測試也可能發現未預期的問題。自動化測試則可以高效地重複執行標準測試。
  • Black Box vs. White Box Testing(黑盒 vs. 白盒測試):黑盒測試中只能從外部測試;白盒測試中有程式碼存取權限,可以針對個別函式撰寫測試,也可以自動化更多測試項目。

Step 1:確認是黑盒還是白盒測試?#

盡早確認測試類型,以調整測試策略。

Step 2:誰會使用它?為什麼?#

軟體通常有多種目標用戶。例如測試瀏覽器的家長管控功能:

  • 父母(設定管控的人)
  • 孩子(接受管控的人)
  • 訪客(既非設定者也非對象)

Step 3:使用情境有哪些?#

父母的情境:安裝軟體、更新管控設定、刪除管控、個人上網使用。 孩子的情境:存取合法內容、嘗試存取被封鎖的內容。

Step 4:使用範圍的邊界為何?#

「封鎖網站」具體代表什麼?

  • 只封鎖特定頁面,還是整個網域?
  • 軟體是基於黑白名單,還是自動學習?
  • 可接受的誤判率是多少?

Step 5:壓力/失效條件為何?#

軟體失效時應如何表現?例如瀏覽器家長管控失效時,應放行被封鎖的網站(而非崩潰),或可以考慮允許父母用密碼覆寫。

Step 6:測試案例與如何執行測試?#

結合手動和自動化測試。將測試分解為主要元件,系統性地覆蓋所有情境。

不要一股腦地列出所有能想到的案例。先拆解主要元件,再有條理地產出測試案例,展現你的結構化思維。


測試函式#

測試函式通常是最簡單的測試類型,討論範圍較小,主要聚焦在驗證輸入和輸出。

範例:為 sort(int[] array) 撰寫測試程式碼。

Step 1:定義測試案例#

  • 正常情況(The normal case):一般輸入是否產生正確輸出?要考慮邊界情況,例如奇數個元素(無法均分)。
  • 極端情況(The extremes):空陣列?只有一個元素的陣列?非常大的陣列?
  • Null 與非法輸入(Nulls and “illegal” input):傳入 null 時應如何處理?
  • 奇特輸入(Strange input):已經排序好的陣列?逆序排列的陣列?

Step 2:定義預期結果#

通常預期結果很明顯,但有時需要更細緻的驗證。例如:如果 sort 應該回傳新的已排序陣列,需要確認原陣列沒有被修改。

Step 3:撰寫測試程式碼#

void testAddThreeSorted() {
    MyList list = new MyList();
    list.addThreeSorted(3, 1, 2); // Adds 3 items in sorted order
    assertEquals(list.getElement(0), 1);
    assertEquals(list.getElement(1), 2);
    assertEquals(list.getElement(2), 3);
}

問題排查題#

問題排查題要求你說明如何除錯或診斷一個已知問題。

範例:你在 Google Chrome 團隊,收到一個 bug 報告:Chrome 在啟動時崩潰。你會怎麼做?

重新安裝軟體可能解決單一用戶的問題,但無法幫助其他有相同問題的用戶。目標是找出根本原因,讓開發者能修復它。

Step 1:了解情境(Understand the Scenario)#

先問問題,盡可能了解情況:

  • 用戶遭遇此問題多久了?
  • 瀏覽器版本?作業系統版本?
  • 問題是否每次都發生?發生的頻率和時機?
  • 是否有錯誤報告?

Step 2:拆解問題(Break Down the Problem)#

將瀏覽器啟動流程拆解為可測試的步驟:

  1. 從 Windows 開始選單啟動
  2. 點擊 Chrome 圖示
  3. 瀏覽器實例啟動
  4. 瀏覽器載入設定
  5. 瀏覽器發出 HTTP 請求取得首頁
  6. 瀏覽器收到 HTTP 回應
  7. 瀏覽器解析網頁
  8. 瀏覽器顯示內容

在這個流程中的某個點,發生了崩潰。優秀的測試者會逐步排查,找出問題所在。

Step 3:建立具體且可執行的測試(Create Specific, Manageable Tests)#

每個步驟應對應具體可行的驗證方式,可以是:

  • 請用戶執行的指示(簡單、實際)
  • 你可以自己複製的步驟(在自己的機器上重現)

在實際工作中,你面對的是真實客戶,不能給出他們無法執行或不願執行的指示。測試計畫必須實用可行。


面試題目列表#

題號題目
11.1Mistake:找出程式碼中的錯誤(使用 unsigned int 的無窮迴圈)
11.2Random Crashes:應用程式隨機崩潰,找出可能的程式錯誤
11.3Chess Test:測試棋盤遊戲中的 canMoveTo(int x, int y) 方法
11.4No Test Tools:不使用測試工具,如何對網頁進行載入測試?
11.5Test a Pen:如何測試一支筆?
11.6Test an ATM:如何在分散式銀行系統中測試 ATM?