解密邏輯的測試有一個特別之處:你沒辦法簡單地「準備一份輸入,斷言輸出結果」,因為輸入本身(加密過的片段)長什麼樣,取決於加密的金鑰、IV、演算法——如果測試資料是隨便找一段看起來像加密內容的亂數,根本沒辦法驗證解密邏輯有沒有正確還原出原始內容。
from Cryptodome.Cipher import AES
from Cryptodome.Util.Padding import pad
def build_encrypted_fixture(plain_content: bytes, key: bytes) -> bytes:
cipher = AES.new(key, AES.MODE_CBC) # 沒指定 IV,函式庫會自動產生一組隨機 IV
return cipher.encrypt(pad(plain_content, AES.block_size))
測試時反過來操作:先決定「解密後應該長什麼樣」(plain_content),用已知的金鑰把它加密成 fixture,再讓被測試的解密邏輯去解這份 fixture,斷言解密結果等於一開始設定的 plain_content。 這樣測試就有一個明確、可驗證的正確答案,不是只憑「看起來像有解密」這種主觀判斷。
如果測試資料是複製一份真實來源的加密片段,測試能驗證的只有「這個特定片段解密後不會拋例外」,沒辦法確認解密結果是不是真的正確——因為你不知道這份片段解密後「應該」長什麼樣。反向產生的 fixture 因為明確知道加密前的原始內容,才能真正驗證解密邏輯的正確性,而不只是驗證它「有跑起來」。
這個做法能成立,前提是測試程式碼要能完全掌握加密用的金鑰跟 IV——用已知的金鑰產生加密內容,被測試的解密邏輯要用同一把金鑰、對應的 IV,才能正確還原。如果被測試的程式碼裡金鑰或 IV 是從外部(例如網路請求)取得,測試時就需要搭配 Day 23 的 mock 技巧,讓被測試的程式碼在測試環境裡拿到跟 fixture 產生時一致的金鑰。
你測試過任何形式的編碼/解碼、加密/解密邏輯嗎?你的測試資料是真實環境擷取來的,還是反向產生、明確知道正確答案的?
明天講固定資料(fixture)的設計取捨:要多真實才夠,全真實內容 vs 只留測試需要的片段。