今天將介紹如何在 Python 中實踐測試驅動開發(TDD)。透過 TDD,我們能在程式開發的初期就撰寫測試案例,以確保每個新功能都符合需求,並且通過測試。這種方法可以大幅提升程式的可靠性與可維護性。
測試驅動開發是一種軟體開發流程,強調在撰寫功能代碼之前先撰寫測試。開發者首先撰寫會失敗的測試,然後實作能通過這些測試的代碼,最後進行代碼重構以確保最佳實踐。
unittest
模組介紹unittest
是 Python 內建的單元測試框架,適合進行 TDD。它能夠自動執行測試並報告結果,並提供了豐富的測試工具。
import unittest
def add(x, y):
return x + y
class TestMath(unittest.TestCase):
def test_add(self):
self.assertEqual(add(2, 3), 5)
self.assertEqual(add(-1, 1), 0)
if __name__ == '__main__':
unittest.main()
這段程式展示了如何利用 unittest
來測試一個簡單的加法函數。
我們將透過 TDD 的方法,開發一個階乘函數。首先撰寫測試案例,然後實作功能,再進行重構。
import unittest
class TestMathFunctions(unittest.TestCase):
def test_factorial(self):
self.assertEqual(factorial(5), 120)
if __name__ == '__main__':
unittest.main()
在這裡,我們還沒有實作 factorial
函數,測試將失敗。
factorial
函數def factorial(n):
if n == 0:
return 1
result = 1
for i in range(1, n + 1):
result *= i
return result
這個階段,我們實作了 factorial
函數,並再次執行測試,應該會通過。
檢查程式碼是否可以進行簡化或改進。例如,利用遞迴來簡化階乘函數:
def factorial(n):
return 1 if n == 0 else n * factorial(n - 1)
setUp
和 tearDown
方法在某些情況下,你可能需要在測試之前準備一些環境或資源(例如建立資料庫連線)。setUp
方法在每個測試之前執行,tearDown
方法則在測試後執行。
import unittest
class TestExample(unittest.TestCase):
def setUp(self):
print("執行測試之前的初始化")
def tearDown(self):
print("測試結束後的清理工作")
def test_sample(self):
self.assertEqual(1 + 1, 2)
if __name__ == '__main__':
unittest.main()
在某些情況下,你可能需要測試程式是否正確處理例外。例如,測試除以 0 時是否會引發錯誤。
import unittest
def divide(x, y):
if y == 0:
raise ValueError("不能除以 0")
return x / y
class TestDivideFunction(unittest.TestCase):
def test_divide_by_zero(self):
with self.assertRaises(ValueError):
divide(10, 0)
if __name__ == '__main__':
unittest.main()
練習 1: 撰寫一個計算質數的函數,並使用 TDD 方法完成測試與實作。
練習 2: 為一個數學函數庫撰寫測試,包含加法、減法、乘法和除法的測試。
Test-Driven Development (TDD) 是在編寫功能代碼之前,先撰寫測試用例的開發方式,這確保了功能代碼完全滿足測試要求。以下是實作計算質數的步驟。
import unittest
# 測試用例
class TestPrimeFunction(unittest.TestCase):
def test_prime_number(self):
self.assertTrue(is_prime(7)) # 7 是質數
def test_non_prime_number(self):
self.assertFalse(is_prime(4)) # 4 不是質數
def test_one_is_not_prime(self):
self.assertFalse(is_prime(1)) # 1 不是質數
def test_prime_large_number(self):
self.assertTrue(is_prime(29)) # 29 是質數
# 運行單元測試
if __name__ == '__main__':
unittest.main()
def is_prime(n):
if n <= 1:
return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
return False
return True
is_prime
函數判斷一個數是否為質數。若數字小於或等於 1,返回 False
。若能被 2 到該數的平方根之間的任何數整除,也不是質數。is_prime
函數,通過測試。這裡,我們會建立一個數學函數庫,並使用 unittest
為其撰寫單元測試。TDD 的流程同樣適用於這裡。
import unittest
# 測試用例
class TestMathFunctions(unittest.TestCase):
def test_add(self):
self.assertEqual(add(3, 4), 7)
def test_subtract(self):
self.assertEqual(subtract(10, 5), 5)
def test_multiply(self):
self.assertEqual(multiply(3, 4), 12)
def test_divide(self):
self.assertEqual(divide(8, 2), 4)
def test_divide_by_zero(self):
with self.assertRaises(ZeroDivisionError):
divide(10, 0)
# 運行單元測試
if __name__ == '__main__':
unittest.main()
def add(a, b):
return a + b
def subtract(a, b):
return a - b
def multiply(a, b):
return a * b
def divide(a, b):
if b == 0:
raise ZeroDivisionError("除數不能為 0")
return a / b
add
、subtract
、multiply
和 divide
根據測試要求編寫。divide
函數會在除數為 0 時拋出 ZeroDivisionError
,並通過測試 assertRaises
來檢查此行為。這樣的測試驅動開發 (TDD) 方法,能夠確保程式碼的正確性並便於後續維護。撰寫測試能防止潛在的邏輯錯誤,也有助於提升開發過程的品質。
今天的課程介紹了 TDD 的基本流程及 Python 的 unittest
模組。透過 TDD,你能在程式開發過程中更有條理地編寫代碼,並確保所有功能通過測試,這能幫助你更有效率地構建穩定的應用程式。