单元测试框架

; 单元测试框架GBK编码
(defun test-+ ()
  (and
    (= (+ 1 2) 3)
    (= (+ 1 2 3) 6)
    (= (+ -1 -3) -4)))
; 显示某条用例是否通过
(defun test-+ ()
  (format t "~:[失败~;通过~] ... ~a~%" (= (+ 1 2) 3) '(= (+ 1 2) 3))
  (format t "~:[失败~;pass~] ... ~a~%" (= (+ 1 2 3) 6) '(= (+ 1 2 3) 6))
  (format t "~:[失败~;pass~] ... ~a~%" (= (+ -1 -2) -3) '(= (+ -1 -2) -3)))
; 重构
(defun report-result (result form)
  (format t "~:[失败~;通过~] ... ~a~%" result form))
(defun test-+ ()
  (report-result (= (+ 1 2) 3) '(= (+ 1 2) 3))
  (report-result (= (+ 1 2 3) 6) '(= (+ 1 2 3) 6))
  (report-result (= (+ -1 -2) -3) '(= (+ -1 -2) -3)))
; 重构2,宏,语法层面上的替换
; (check (= (+ 1 2) 3))
; (report-result (= (+ 1 2) 3) '(= (+ 1 2) 3))
(defmacro check (form)
  `(report-result ,form ',form))
(defun test-+ ()
  (check (= (+ 1 2) 3))
  (check (= (+ 1 2 3) 6))
  (check (= (+ -1 -2) -3)))
; 重构3
(defmacro check (&rest forms)
  `(progn
    ,@(loop for f in forms collect `(report-result ,f ',f))))
 
(defun test-+ ()
  (check
    (= (+ 1 2) 3)
    (= (+ 1 2 3) 6)
    (= (+ -1 -2) -4)))
; 等价于
; (defun test-+ ()
; (progn
; (report-result (= (+ 1 2) 3) '(= (+ 1 2) 3))
; (report-result (= (+ 1 2 3) 6) '(= (+ 1 2 3) 6))
; (report-result (= (+ -1 -2) -3) '(= (+ -1 -2) -3))))
 
; 修复返回值
(defun report-result (result form)
  (format t "~:[失败~;通过~] ... ~a~%" result form)
  result)
; and存在短路行为出错就返回了,不能用and代替progn,写一个宏
; (combile-result
; (foo)
; (bar)
; (baz))
; 让他等同于
; (let ((result T))
; (unless (foo) (setf result nil ))
; (unless (bar) (setf result nil))
; (unless (baz) (setf result nil))
; result)
 
 
(defmacro combile-result (&rest forms)
  (let ((result (gensym)))
    `(let ((,result t))
      ,@(loop for f in forms collect `(unless ,f (setf ,result nil)))
      ,result)))
 
(defmacro check (&rest forms)
  `(combile-result
    ,@(loop for f in forms collect `(report-result ,f ',f))))
 
; 如果有另外一个函数
(defun test-* ()
  (check
    (= (* 2 2) 4)
    (= (* 4 5) 20)))
 
; 一起测试
(defun test-arithmetic ()
  (combile-result
    (test-+)
    (test-*)))
; 确切的知道哪个函数没通过
(defvar *test-name* nil)
(defun report-result (result form)
  (format t "~:[失败~;通过~] ... ~a:~a~%" result *test-name* form))
(defun test-+ ()
  (let ((*test-name* 'test-+))
    (check
      (= (+ 1 2) 3)
      (= (+ 1 2 3) 6)
      (= (+ -1 -2) -4))))
 
(defun test-* ()
  (let ((*test-name* 'test-*))
  (check
    (= (* 2 2) 4)
    (= (* 4 5) 20))))
; 抽象诞生
; 上述代码引入了重复每次都需要绑定*test-name*
; 部分抽象是很糟糕的,需要完整抽象
(defmacro defuntest (name parameters &body body)
  `(defun ,name ,parameters
    (let ((*test-name* ',name))
      ,@body)))
 
(defuntest test-+ ()
  (check
      (= (+ 1 2) 3)
      (= (+ 1 2 3) 6)
      (= (+ -1 -2) -4)))
(defuntest test-* ()
  (check
     (= (* 2 2) 4)
     (= (* 4 5) 20)))
 
; 测试层次体系
; 第一层 test-+ test-*
; 第二层 test-arithmetic
; ......
; 需要把层次显示出来
(defmacro defuntest (name parameters &body body)
  `(defun ,name ,parameters
    (let ((*test-name* (append *test-name* (list ',name))))
      ,@body)))
(defuntest test-+ ()
  (check
      (= (+ 1 2) 3)
      (= (+ 1 2 3) 6)
      (= (+ -1 -2) -4)))
(defuntest test-* ()
  (check
     (= (* 2 2) 4)
     (= (* 4 5) 20)))
(defuntest test-arithmetic ()
  (combile-result
    (test-+)
    (test-*)))
 
(defuntest test-math ()
  (test-arithmetic))




posted @ 2012-04-11 08:45  舜耕山翁  阅读(147)  评论(0编辑  收藏  举报