[英]Unit testing of destructive functions in lisp
這里的背景是我有一個 function 的非破壞性版本,出於性能原因我想使其具有破壞性。 然而,編寫單元測試變得具有挑戰性,因為 lisp 將源代碼中的所有引用列表視為常量,更改這些會導致未定義的行為。
我使用降落傘作為單元測試框架
例如,
(define-test suite-1
(let ((start '((1 2) (3 4) (5 6)))
(end '((7 1 2) (3 4) (5 6))))
(is #'equal end (push 7 (car start))))
(let ((start '((1 2) (3 4) (5 6)))
(end '((8 1 2) (3 4) (5 6))))
(is #'equal end (push 8 (car start)))))
這有點失敗,因為我們最終將8
推入常量列表(1 2)
最終導致(push 8 (car start))
導致(8 7 1 2)
而不是預期的(8 1 2)
這不是測試非破壞性函數的問題,因為它們不修改常量。 這在單元測試之外也不是問題,因為我知道將不再需要原始結構。
我可以用這個丑陋的東西代替上面的東西:-
(let ((start (list (list 1 2) (list 3 4) (list 5 6))) ...
然后創建一個適當的非常量列表,但它確實使代碼不可讀......
關於其他人如何處理這個問題的任何建議?
使用COPY-TREE
對引用列表結構進行深度復制。
(let ((start (copy-tree '((1 2) (3 4) (5 6)))))
...
)
你的例子有幾個錯誤。
(define-test suite-1
(let ((start '((1 2) (3 4) (5 6)))
(end '((7 1 2) (3 4) (5 6))))
(is #'equal end (push 7 (car start))))
(let ((start '((1 2) (3 4) (5 6)))
(end '((8 1 2) (3 4) (5 6))))
(is #'equal end (push 8 (car start)))))
這是兩個獨立的let
表達式。 意思是,第一個表達式的start
- 無論您對其應用什么破壞性的 function - 都不會影響第二個表達式的start
。 從那以后,它是使用相同的引用列表表達式新創建的。
其次, (push 7 (car start))
不返回整個start
內容,因此它只返回start
的修改后的car
。 所以不能和end
比較,應該和(car end)
比較,看是否equal
。 如果你這樣做,你的代碼應該運行。 我通過以下方式對其進行了測試:
(defun test ()
(let ((start '((1 2) (3 4) (5 6)))
(end '((7 1 2) (3 4) (5 6))))
(assert (equal (car end) (push 7 (car start)))))
(let ((start '((1 2) (3 4) (5 6)))
(end '((8 1 2) (3 4) (5 6))))
(assert (equal (car end) (push 8 (car start)))))
(print "successfully run through."))
;; and then run:
(test)
;;
;; "successfully run through."
'' "successfully run through."
所以assert
被滿足了。
SBCL 警告對常量數據應用破壞性 function。 但是常量數據僅適用於您正在使用的let
表達式。 但在它之外,在一個新的let
表達式中,一個'((1 2) (3 4) (5 6))
總是會產生相同的列表。
當我看到您的示例時,我簡直不敢相信 - 如果您使用(car end)
來測試equal
性,它會在第二個表達式中給出除T
之外的任何其他內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.