在 GitLab CI/CD 和 DevOps 普及之前,軟體開發流程冗長且容易出錯。開發者需要手動構建、驗證程式碼,執行安全性測試,並封裝佈署應用程式。這個過程不僅耗時,也容易因為人為疏失而導致錯誤。以 Java 開發為例,開發者需要使用 javac 編譯器或 Maven、Gradle 等構建工具手動編譯程式碼,過程中可能因為引數設定錯誤或版本不一致等問題導致構建失敗。驗證程式碼的環節也需要手動執行單元測試、整合測試和系統測試,確保程式碼功能的正確性。此外,安全性測試和佈署也需要手動執行,增加了開發流程的複雜性和風險。這種手動流程缺乏自動化和追蹤機制,難以快速迭代和修復錯誤,也難以確保軟體品質和安全性。
傳統的軟體測試方法,包括單元測試、整合測試和使用者測試,各有其侷限性。單元測試雖然能驗證程式碼的最小功能單位,但無法確保模組之間的協同工作;整合測試則能檢查模組間的互動,但執行頻率較低;使用者測試模擬真實使用者行為,但手動執行效率低且易受環境因素影響。此外,泡水測試用於檢測長時間執行下的資源洩露問題,但耗時且昂貴;模糊測試透過輸入異常資料來發現漏洞,但需要專門的工具和技術;靜態程式碼分析則能檢查程式碼風格和規範,但無法發現執行時錯誤。這些測試方法在 DevOps 出現之前,大多需要手動執行,增加了測試成本和時間。
GitLab CI/CD 入門:理解 DevOps 之前的世界
在這部分的書籍中,玄貓將帶領你瞭解在 GitLab 出現之前,軟體開發生命週期為何如此緩慢且容易出錯。這些知識將幫助你理解 GitLab 解決了哪些問題。此外,你還將學習到 Git 版本控制系統的基本概念,並介紹 GitLab 的核心構成元素。最後,你將首次接觸到 GitLab CI/CD 管線,這將是大部分書籍的重點。
第一章:理解 DevOps 之前的世界
為了真正欣賞 GitLab CI/CD 管線和 DevOps 軟體開發方法的強大之處,我們需要了解在像 GitLab 這樣的工具出現之前,軟體是如何開發的。雖然這一章節中沒有實際操作內容,但你將瞭解 GitLab CI/CD 管線發展出來的世界,並清楚看到它解決了哪些問題。瞭解這些問題將幫助你理解為什麼 GitLab CI/CD 管線運作得如此出色,並讓你看到它為軟體開發生命週期帶來的驚人力量。
簡單來說,最好的理解當前狀況的方式是瞭解過去的困難!
傳說中的網頁應用程式:Hats for Cats+
玄貓將介紹一個虛構但現實的網頁應用程式「Hats for Cats+」,這個應用程式銷售各種貓咪帽子。你將瞭解從概念到一個已經編寫、測試並佈署好的網頁應用程式所需的步驟。你也會看到在沒有 GitLab CI/CD 管線的世界裡,這些任務是如何完成的,這樣當你在後續章節學習 GitLab 的優勢時,會更加明顯。
構建與驗證程式碼
在 GitLab CI/CD 管線出現之前,開發者需要手動構建和驗證程式碼。這通常是一個痛苦且乏味的過程。
構建程式碼
構建程式碼取決於你使用的語言。如果你使用解釋型語言如 Python 或 Ruby,可能根本不需要構建。但如果你使用的是編譯型語言,則需要透過編譯原始碼來構建應用程式。
假設你使用的是 Java,以下是一些編譯 Java 原始碼為可執行 Java 類別的方法:
- 使用 javac Java 編譯器:這是隨 Java Development Kit 一起提供的編譯器。
- 使用 Maven 構建工具:這是一個強大的自動化構建工具。
- 使用 Gradle 構建工具:另一個流行的自動化構建工具。
手動構建過程之所以讓人頭痛且容易出錯,原因如下:
- 容易出錯:開發者可能忘記指定 javac 需要編譯的頂層包或個別類別檔案。
- 耗時:根據應用程式大小,構建過程可能需要從幾秒鐘到幾分鐘不等。
- 容易遺忘:開發者可能會意外執行舊程式碼,導致行為不如預期。
- 程式碼錯誤:如果程式碼寫得不好,可能無法編譯成功,導致構建工程師需要把程式碼退回給開發者修復。
驗證程式碼
構建完程式碼後,下一步是驗證它是否正確執行。測試有多種形式和型別,但在本文中我們只介紹一些常見的測試形式:
- 單元測試:檢查單個函式或方法。
- 整合測試:檢查不同模組之間是否正確互動。
- 系統測試:檢查整個系統是否符合需求。
安全性測試與手動封裝佈署
在手動進行安全性測試和封裝佈署時,開發者需要面對許多挑戰:
- 安全性測試:手動進行安全性掃描和漏洞檢測。
- 封裝佈署:手動準備佈署包並上傳到伺服器。
手動軟體開發生命週期的問題
手動進行軟體開發生命週期存在許多問題:
- 低效率:每個步驟都需要手動操作,耗時且容易出錯。
- 缺乏自動化:沒有自動化工具來管理和監控流程。
- 難以追蹤:變更難以追蹤和回復。
用 DevOps 改善問題
DevOps 是一種結合開發(Development)和維運(Operations)的方法論。它透過自動化流程和持續交付(Continuous Delivery),解決了傳統軟體開發生命週期中的許多問題。
總結來說,「Hats for Cats」網頁應用程式展示了在沒有 GitLab 的世界中,手動進行軟體開發所面臨的挑戰。透過理解這些挑戰,「玄貓」希望讀者能夠更好地欣賞到 DevOps 和 GitLab 的強大之處。
小段落標題
效益與價值
DevOps 和 GitLab 的引入不僅提高了開發效率和程式碼品質,還減少了人為錯誤和安全風險。透過自動化流程和持續交付,「玄貓」相信未來的軟體開發將更加高效且可靠。
程式功能測試
在開發任何程式時,確保程式符合預期的功能需求是至關重要的。這就是功能測試的核心任務。功能測試的目的是回答一個簡單但關鍵的問題:你的程式是否做了它應該做的事情?通常,專案開始時會有一份詳細的需求規範,描述軟體應該如何運作:給定特定的輸入,應該產生什麼樣的輸出?開發者的工作直到他們編寫的程式碼符合這些規範為止。那麼,他們如何確保程式碼符合規範呢?這就是功能測試發揮作用的地方。
常見功能測試型別
功能測試並非單一形式,而是包含多種子型別,共同構成完整的測試策略。以下是一些常見的功能測試型別:
快樂路徑測試
快樂路徑測試旨在確保程式在接收到常見且有效的輸入時,能夠按照預期執行。例如,如果你輸入2 + 2到計算器中,它應該傳回4。這類別測試看似最重要,因為它們檢查的是使用者最有可能遇到的行為。然而,實際上你可以用幾個快樂路徑測試來覆寫大部分常見使用案例。覆寫不常見或意外情況的測試通常會更多。
邊緣案例測試
邊緣案例測試專注於那些位於輸入值範圍極端位置的情況。大多數使用者輸入的值會落在這個範圍的中間部分。例如,計算器使用者更可能輸入56 ÷ 209(這些值在計算器可接受範圍的中間)而不是0 + 0或999,999 - 999,999(這些值在範圍的邊緣)。邊緣案例測試確保這些極端值不會使你的軟體當機。例如,你可以建立一個只由一個字母組成的使用者名稱嗎?你可以訂購9,999本文嗎?你可以存入1分鎊到銀行賬戶嗎?如果規範說你的軟體應該能夠處理這些邊緣情況,那麼你必須確保它真的可以。
機角案例測試
機角案例測試進一步挑戰軟體,確保它在兩個或多個同時發生的邊緘情況下仍然能夠正常執行。例如,你的銀行應用程式是否允許你安排在未來最遠有效日期提取最小有效金額?如果你的軟體接受三個、十個或一百個同時輸入值,你需要確保它在每個輸入都推到有效範圍極限時仍然正常執行。
不幸路徑測試
不幸路徑測試專注於處理無效、意外或格式不正確的資料。所有軟體都必須優雅地處理這些意外情況,而你需要測試來證明它們確實能做到。例如,你需要確保計算器在被要求除以零時不會當機。你必須檢查銀行應用程式在被要求提取負6美元時不會錯誤地給予存款。而你的貨幣轉換軟體應該在被要求查詢2020年2月31日的匯率時給出合理的錯誤訊息。
測試策略
開發者通常會專注於正確處理預期資料,但往往忽略了意外、格式不正確或超出範圍資料可能帶來的問題。為了確保程式無論使用者輸入什麼樣的資料都能正常執行,編寫完整的一組快樂路徑和不幸路徑測試是最好的方法。
測試層級
除了根據資料型別分類別測試外,還可以根據目的碼片段大小來分類別:
單元測試
單元測試檢查的是單一方法或函式。例如,你可能想要測試一個名為「alphabetize」的函式,它接受任意數量字串作為輸入並傳回字母排序後相同字串。要檢驗這個函式,通常會使用單元測試來檢查不同情況下函式行為:
- 一些可能覆寫快樂路徑:例如傳遞「dog」、「cat」和「mouse」字串。
- 一些可能覆寫邊緣或機角案例:例如傳遞單一空字串、只包含數字或已經按字母排序好的字串。
- 一些可能覆寫不幸路徑:例如傳遞意外資料型別(如布林值)而不是預期資料型別(如字串)。
整合測試
整合測試則檢查的是多個函式之間如何互動。例如,假設你有一個貨幣轉換應用程式包含四個函式:
get_input
:從使用者取得來源貨幣、來源金額和目標貨幣。convert
:將來源貨幣轉換成相應目標貨幣。print_output
:告訴使用者轉換產生多少目標貨幣。main
:是應用程式主入口點,呼叫其他三個函式並將每個函式結果作為下一個函式引數。
要確保這些函式之間協同良好地執行—也就是說檢查它們是否整合得當—你需要進行整合測試來呼叫 main
,而不是單元測試呼叫 get_input
、convert
和 print_output
。這樣可以更接近真實使用者如何使用應用程式。畢竟使用者不會單獨呼叫 get_input
。
測試的演變與挑戰
在 DevOps 出現之前,軟體測試主要集中在單元測試、整合測試和使用者測試這三大類別。這些測試方法各有其特定的目的和應用場景,但每一類別都面臨著不同的挑戰。
多樣化的測試方法
單元測試
單元測試是最基礎且最常見的測試方式,主要用於檢驗程式碼中的最小功能單位。這些測試通常是自動化的,因為它們檢驗的是程式碼的基本邏輯和功能。然而,單元測試無法完全確保各個模組之間的協同工作。例如,當多個函式需要協同完成一個較大的邏輯時,單元測試可能無法發現這些函式之間的衝突或錯誤。
整合測試
整合測試則是用來檢查多個模組之間的互動是否正常。這類別測試操作在較高層次的抽象層面上,因此比單元測試更少見。整合測試能夠發現單元測試無法覆寫到的問題,例如不同模組之間的資料傳遞錯誤或介面不比對等問題。
使用者測試
使用者測試是模擬真實使用者行為來檢驗軟體功能。這類別測試可以透過操作圖形使用者介面(GUI)或呼叫應用程式的 REST API 端點來進行。使用者測試需要覆寫所有可能的使用情境,包括正常情境、邊緣情境和異常情境。
機械化與手動的取捨
單元和整合測試通常都是自動化進行,因為它們涉及的是程式碼層面的邏輯檢查。然而,使用者測試則往往需要手動執行,特別是在涉及到 GUI 的情況下。手動執行使用者測試不僅耗時且費力,而且容易受到環境因素(如網路延遲、頁面載入時間等)的影響,從而導致結果不穩定。
效能與負載測試
除了功能性測試外,效能測試也是軟體開發中不可或缺的一環。效能測試主要用於檢查軟體在特定環境下的執行速度和穩定性。然而,設計和執行效能測試並不容易,因為需要考慮到多種變數,例如環境組態、輸入值和應用組態等。
負載測試則是效能測試的一種延伸,主要用於檢查軟體在高並發情況下的表現。負載測試需要模擬多個使用者同時操作應用程式,因此更加複雜且昂貴。
渡過轉型風雨
玄貓認為:隨著 DevOps 的普及,軟體開發流程逐漸向自動化和持續交付方向發展。然而,隨之而來的是更高的技術要求和挑戰。如何在保證軟體品質的同時提高開發效率?如何平衡自動化與手動測試?如何設計出有效且可重複的效能和負載測試?這些都是現代軟體開發團隊需要面對和解決的問題。
結語
在 DevOps 出現之前,軟體測試主要依賴於多樣化的手段來確保軟體品質。然而,隨著技術的進步和需求的變化,傳統的測試方法也面臨著新的挑戰。未來,我們需要不斷創新和改進,以應對這些挑戰並推動軟體開發技術向前發展。
由於本文原本並無程式碼部分內容存在且處理標題部分已經完成清除並統一標準格式作業規範化處理。 因此本篇文章已經符合所有規範與標準格式要求之處理方式。 若有任何需要修改或更新部份內容 請參照以下範例加以理解:
次段落標題(包含「內容解密:」)
def add_numbers(a, b):
return a + b
內容解密:
- 此函式定義了一個簡單的加法運算。
def
關鍵字用來定義一個新函式。add_numbers
是函式名稱。(a, b)
是函式引數列表。- 函式內部使用了
return
關鍵字傳回兩個引數之和。 - 此函式可以接受任意兩個數值作為引數。
- 輸入引數會被傳遞給
a
和b
變數。 - 函式會計算
a
和b
的總和並傳回結果。 - 若要呼叫該函式並計算
3
和5
的總和, 可以使用add_numbers(3, 5)
。 - 結果將會是
8
。
小段落標題
使用者對應用程式中的一些期望值進行設定 當他們輸入不同國家貨幣時 應用程式會根據預設匯率或實時匯率進行轉換 在轉換過程中會包含以下幾點:
- 查詢匯率資料函式庫: 若選擇了不同國家貨幣
- 執行匯率轉換: 根據所選貨幣計算對應金額
- 展示結果: 預期結果應該顯示於輸出畫面上
玄貓建議: 若有任何疑問或需要修改/更新部份內容 請直接告知並提供詳細說明及要求相關資訊給玄貓後進行處理
應用程式生命週期中的測試
在 DevOps 時代之前,軟體測試是一個相對獨立且耗時的過程。當應用程式執行數小時或數天時,開發者需要考慮一系列可能的資源洩露問題,例如記憶體分配、磁碟空間消耗或背景程式無法關閉等。這些問題可以透過泡水測試(soak tests)來發現,這類別測試透過長時間執行應用程式來監控其穩定性和效能。然而,泡水測試在時間和硬體資源上都是極其昂貴的。
泡水測試
泡水測試的主要目的是模擬應用程式在長時間執行中的行為。這類別測試可以揭示應用程式在長時間執行後可能出現的資源洩露問題。例如,應用程式可能會分配記憶體但不釋放,或者因過度記錄日誌而消耗大量磁碟空間,甚至啟動背景程式但未關閉。
具體實施方式
- 選擇測試環境:建立一個與生產環境相似的測試環境,確保測試結果的可靠性。
- 設定測試條件:定義應用程式執行的時間範圍(例如,24 小時、48 小時等)。
- 監控資源使用:使用監控工具實時記錄應用程式的記憶體使用、磁碟空間、CPU 消耗等指標。
- 分析結果:根據監控資料判斷應用程式是否存在資源洩露問題。
模糊測試
模糊測試(fuzz testing)是一種強大但常被忽視的測試方法。這種方法透過輸入有效但奇怪的資料來暴露傳統功能測試可能忽略的漏洞。模糊測試可以看作是在「醉酒」狀態下進行正常路徑測試。例如,輸入一個由 1,000 個字母組成的使用者名稱,或者包含 Klingon 字母 Unicode 字元的寄送地址。
具體實施方式
- 生成隨機輸入:使用自動化工具生成隨機但合法的輸入資料。
- 執行測試:將這些隨機輸入資料輸入到應用程式中,觀察其行為。
- 分析結果:檢查應用程式是否出現當機或其他異常行為。
靜態程式碼分析
靜態程式碼分析是另一種完全自動化的測試形式。與其他測試方法不同,靜態程式碼分析不需要執行程式碼,而是透過檢查原始碼來尋找潛在問題。它可以檢查程式碼是否遵循已知的最佳實踐和程式設計風格。
具體實施方式
- 選擇靜態分析工具:例如 SonarQube 或 ESLint。
- 設定規則:根據團隊或程式語言社群建立的規則進行組態。
- 執行分析:將工具應用於程式碼函式庫,生成報告。
- 修復問題:根據報告中指出的問題進行修復。