Существует ли фреймворк для насмешек/заглушек для Common Lisp?
EmacsLispMock выглядит великолепно, но это фреймворк Emacs lisp, и я ищу что-нибудь из Common Lisp, которое можно было бы использовать.
Какие-либо предложения?
Существует ли фреймворк для насмешек/заглушек для Common Lisp?
EmacsLispMock выглядит великолепно, но это фреймворк Emacs lisp, и я ищу что-нибудь из Common Lisp, которое можно было бы использовать.
Какие-либо предложения?
Следующее должно делать то, что вы ищете
(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))
Макрос просто сохраняет функцию, на которую в данный момент указывает символ, и заменяет ее предоставленной реализацией-заглушкой. В конце блока функция восстанавливается до исходного значения.
Вероятно, имеет смысл добавить защиту от нелокальных выходов из тела.
Также обратите внимание, что очевидное изменение определения функции не сработает, если вызовы функций были встроены компилятором. В CL есть специальное объявление NOTINLINE, которое можно использовать чтобы предотвратить эту проблему.
unwind-protect. Это довольно простой шаблон, часто встречающийся в макросах.
- person Svante; 10.02.2017
Как указывает Райнер, компилятор файлов иногда встраивает функции, а это означает, что изменение определения функции не будет иметь никакого эффекта в тех местах, где функция была встроена.
Изменение определения имени функции также не заменит использование функции в качестве буквального объекта, например, если вы где-то сохранили #'my-stubbed-function в переменной.
Однако в некоторых реализациях lisp вы можете определить обёртки функций или использовать рекомендации для достижения этого: например, Allegro CL имеет fwrappers. В SBCL вы можете использовать TRACE с нестандартной функцией :break и пользовательским * invoke-debugger-hook*, и я уверен, что в других реализациях lisp будет что-то подобное.
Я не думаю, что кто-то упаковал эти методы заглушки в библиотеку. Ты мог быть первым! (И это было бы здорово. Я бы хотел использовать что-то подобное.)
Разве это не самый простой способ сделать это?
> (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
Я написал библиотеку с макросом, очень похожим на ответ @6502 (with-mocked-functions), но немного более общим. Он также предоставляет with-added-methods, который позволяет вам писать фиктивные методы для ограниченной динамической области. Вы можете найти его здесь: https://github.com/bytecurry/bytecurry.mocks
Вам не нужна насмешливая/заглушенная структура в CL.
Просто создайте новый CLOS, производный от вашего класса класса, с методами, проверенными для того, что вы хотите заглушить/издеваться, и все готово.
Что касается заглушки, почему бы просто не переопределить функцию?
Через несколько лет есть. У нас есть cl-mock и mockingbird в Quicklisp.
(ql:quickload :mockingbird)
Это также позволяет проверить, вызывалась ли функция, если да, то сколько раз и с какими аргументами, а также можно заглушить отдельные методы.
Вы можете попытаться обернуть переопределение функции внутри макроса
(defmacro with-fun (origfn mockfn &body body)
`(let ((it ,origfn))
(setf ,origfn ,mockfn)
,@body
(setf ,origfn ,it)))
Это всего лишь идея, и вам придется реализовать такой макрос. Вы можете поискать в Google profile реализацию, которая делает именно это, заменяет одну функцию другой и добавляет информацию о профилировании. Вы можете позаимствовать некоторые идеи оттуда.
it. Для получения дополнительной информации посетите: en.wikipedia.org/wiki/Anaphoric_macro и en.wikipedia.org/wiki/Hygienic_macro
- person tsikov; 27.09.2016