Closed mdbergmann closed 2 years ago
Could we choose one maybe?
I thought mockingbird had more features, but actually they have the same set? Mockingbird allows to check that a function was called (call-times-for
) and with which arguments (verify-nth-call-args-for
). cl-mock has this with invocations
.
It seems they both do the difference between lexical and dynamic mocks.
I find mockingbird's README way cleaner and the projects looks a tiny bit more lively (3 more stars, 13 more commits and its last commit is more recent by one year \o/ ).
Does cl-mock do something more? Where is its pattern-matching thingy explained?
And BTW, it still relies on and links to Optima which is deprecated.
cl-mock can capture the call arguments and it allows to verify and decide for a return in the answer
call, like this:
(answer (atom-feed:generate-feed feed-model)
(if (not (hash-table-p feed-model))
(cons :nok "Wrong input type")
(cons :ok "<feed")))
feed-model
is the captured call argument. Here you could use pattern matching.
In mockingbird you have to setup separate with-
contexts.
But don't worry. We don't need to add it. I thought there could be two (it seems like they are the only ones). So just close the PR if you think Mockingbird should stay. In any case, I'll check if I can make a PR to cl-mock to change the use of Optima to Trivia.
In any case, I'll check if I can make a PR to cl-mock to change the use of Optima to Trivia.
Cool. I leave this open.
It seems that Mockingbird supports mocking methods (apart from trivial functions). Does cl-mock supports it too?
AFAIK methods in Common Lisp are just implementations of generic functions. I think mocking ordinary functions and generic functions is not very different. From the cl-mock readme:
This small library provides a way to replace the actual implementation of either regular or generic functions with mocks.
While that is written in the readme, there is an issue that mentions this as a TODO feature. So I'm not sure. Give it a try.
But it seems to work:
CL-USER> (defgeneric foo (a))
#<STANDARD-GENERIC-FUNCTION FOO #x302001AD07CF>
CL-USER> (cl-mock:with-mocks ()
(cl-mock:answer (foo a-var) "a-var-mock")
(print (foo "some-string")))
;Compiler warnings :
; In an anonymous lambda form inside an anonymous lambda form: Unused lexical variable A-VAR
"a-var-mock"
"a-var-mock"
A method can be additionally defined and it still works:
CL-USER> (defmethod foo (a) a)
#<STANDARD-METHOD FOO (T)>
btw: cl-mock was changed to use Trivia some time ago.
@vindarel I tried both Mockdingbird and cl-mock and found something below:
with-stubs
(with return value) and with-mocks
(implemented as stubs returning NIL
). cl-mock only has with-mocks
that cover both cases.with-stubs
(lexical) and with-dynamic-stubs
(dynamic). For example you have function foo
that is called by bar
. A lexical stub of foo
will not affect bar
, while a dynamic stub does. cl-mock always uses dynamic stub.answer
macro provided by cl-mock can be used to implement stubs that return different values when given different arguments (keyword arguments etc are also supported). Code example: (answer (foo 10) 42)
returns 42
when (foo 10)
is called, but has no effect when called with 100
. Mockingbird does not have this function. Having said that, I would suggest selecting cl-mock over Mockingbird in the awesome-cl list and introduce cl-mock in the cookbook.
What do you think?
@mdbergmann Please correct me if I made any mistake. :-) (And I appreciate your time to experiment with the generic function thing.)
@sheepduke I haven't looked at Mockingbird, but I trust your comparison is OK. I think both should be added to awesome-cl as probably both have their strengths and weaknesses and maybe it's a matter of choosing.
Ok then, thank you for the detailed comparison. The added line could redirect to this discussion for more details I guess (or a future blog post/gist of yours).
No worries, I've updated my fork.