12 Stimmen

Gibt es ein Mocking/Stubbing-Framework für Common Lisp?

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?

5voto

6502 Punkte 108136

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.

2voto

antifuchs Punkte 121

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).

2voto

Ehvince Punkte 15552

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.

1voto

Marko Punkte 29192

Sie brauchen kein Mocking/Stubbing-Framework in CL.

Erstellen Sie einfach neue CLOS abgeleitet von Ihrer Klasse Klasse mit Methoden ovverides für das, was Sie stub/mock wollen und Sie sind fertig.

Was das Stubbing betrifft, warum nicht einfach die Funktion umdefinieren?

1voto

Vijay Mathew Punkte 25917

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.com

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.

Powered by:

X