Gibt es ein Mocking/Stubbing-Framework für Common Lisp?
EmacsLispMock sieht toll aus, aber es ist ein Emacs-Lisp-Framework, und ich bin auf der Suche nach etwas von Common Lisp zu verwenden.
Irgendwelche Vorschläge?
Gibt es ein Mocking/Stubbing-Framework für Common Lisp?
EmacsLispMock sieht toll aus, aber es ist ein Emacs-Lisp-Framework, und ich bin auf der Suche nach etwas von Common Lisp zu verwenden.
Irgendwelche Vorschläge?
Die folgende Liste sollte das leisten, wonach Sie suchen
(defmacro with-replaced-function (fdef &rest body)
(let ((oldf (gensym))
(result (gensym))
(name (car fdef))
(args (cadr fdef))
(rbody (cddr fdef)))
`(let ((,oldf (symbol-function ',name)))
(setf (symbol-function ',name) (lambda ,args ,@rbody))
(let ((,result (progn ,@body)))
(setf (symbol-function ',name) ,oldf)
,result))))
(defmacro show (x)
`(format t "~a --> ~a~%"
',x ,x))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun foo (x y) (+ x y))
(defun bar (x) (foo x (* x 2)))
(show (bar 42))
(show (with-replaced-function (foo (x y) (* x y))
(bar 42)))
(show (bar 42))
Das Makro speichert einfach die Funktion, auf die das Symbol gerade zeigt, und ersetzt sie durch die bereitgestellte Stub-Implementierung. Am Ende des Blocks wird die Funktion wieder auf den ursprünglichen Wert zurückgesetzt.
Es wäre wahrscheinlich sinnvoll, einen Schutz gegen nichtlokale Austritte aus dem Körper hinzuzufügen.
Beachten Sie auch, dass das Ändern einer Funktionsdefinition natürlich nicht funktioniert, wenn Funktionsaufrufe von einem Compiler eingebettet worden sind. CL hat eine spezielle NOTINLINE Deklaration, die zur Vermeidung dieses Problems verwendet werden kann.
Rainer weist darauf hin, dass der Dateicompiler manchmal Funktionen inlined, was bedeutet, dass eine Änderung der Funktionsdefinition an den Stellen, an denen die Funktion inlined wurde, keine Auswirkungen hat.
Das Ändern der Definition des Funktionsnamens ersetzt auch nicht die Verwendung der Funktion als literales Objekt, z. B. wenn Sie #'my-stubbed-function irgendwo in einer Variablen gespeichert haben.
In einigen Lisp-Implementierungen können Sie jedoch Funktionsumhüllungen definieren oder Hinweise verwenden, um dies zu erreichen: Zum Beispiel hat Allegro CL fwrappers . In SBCL könnten Sie Folgendes verwenden TRACE mit einer nicht standardisierten :break-Funktion und einem benutzerdefinierten *invoke-debugger-hook*, und ich bin mir sicher, dass andere Lisp-Implementierungen etwas ähnliches haben werden.
Ich glaube nicht, dass jemand diese Stubbing-Methoden in eine Bibliothek gepackt hat. Sie könnten der Erste sein! (Und es wäre großartig, ich würde so etwas sehr gerne benutzen).
Ein paar Jahre später ist es so weit. Wir haben cl-mock et Spottdrossel beide in Quicklisp.
(ql:quickload :mockingbird)
Diese erlaubt es auch zu überprüfen, ob eine Funktion aufgerufen wurde, wenn ja wie oft und mit welchen Argumenten und es ist möglich, einzelne Methoden zu stubben.
Ist das nicht der einfachste Weg, dies zu tun?
> (defun b () 'original)
B
> (setf f #'b)
#<Compiled-function B #xC2C1546>
> (defun a () (funcall f))
A
> (a)
ORIGINAL
> (setf f #'(lambda () 'stub))
#<Anonymous Function #xC2D990E>
> (a)
STUB
> (setf f #'b)
#<Compiled-function B #xC2C1546>
> (a)
ORIGINAL
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.