簡體   English   中英

lisp中破壞性函數的單元測試

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM