eproxus / meck

A mocking library for Erlang
http://eproxus.github.io/meck
Apache License 2.0
813 stars 231 forks source link

Introduce support for matchers: #89

Closed horkhe closed 11 years ago

horkhe commented 12 years ago

This pull introduces support for matchers in both expectation creation and history digging functions.

Here is an example how an expectation can be created using matchers:

%% When
meck:expect(Mod, f, [{[1, meck:is(fun(X) -> X == 1 end)],           a},
                     {[1, meck:is(hamcrest_matchers:less_than(3))], b},
                     {['_', '_'],                                   c}]),
%% Then
?assertEqual(a, Mod:f(1, 1)),
?assertEqual(b, Mod:f(1, 2)),
?assertEqual(c, Mod:f(2, 2)).

Here is an example how can be checked if a function has been called during test using matchers:

?assertMatch(true, meck:called(Mod, test, ['_', meck:is(hamcrest_matchers:equal_to(2)), {'_', 3}, "four"]))

As you can see meck:is/1 can create a matcher from any single argument function or a hamcrest matcher. Matchers can be used instead of any expected argument.

horkhe commented 12 years ago

@eproxus What do you think about that?

horkhe commented 12 years ago

Oops, I made a faulty force push. So please hold on with accepting this pull request. Tomorrow I will fix that. Fortunately I have another clone of this repo at work.

horkhe commented 11 years ago

Ok, I am done. Now this pull request brings fully fledged (To reflect that I renamed the pull request) support for matchers. The syntax is uniform on both expectation and verification side.

eproxus commented 11 years ago

Look at the size of that pull request... Will review as soon as I have time. :smiley:

horkhe commented 11 years ago

It brings quite a feature. Besides it is not as big as the previous one :-)

horkhe commented 11 years ago

@eproxus If you could comment on the suggested API now that would be helpful.

horkhe commented 11 years ago

@eproxus off topic: for erlang projects you might wanna give a try to IntelliJ IDEA + Erlang plugin. It appeared just at the end of this August but the author is of the plugin is very active.

eproxus commented 11 years ago
horkhe commented 11 years ago
horkhe commented 11 years ago

@eproxus by the way recently some changes to hamcrest where introduced so I will remove a couple of more lines of code from meck_matcher

horkhe commented 11 years ago

And let's not split this pull request in pieces please for the latter changes depend on passthrough and func being a ret_spec

eproxus commented 11 years ago

Why do the later changes depend on passthrough/0 and func/1 at all? As I see it, those should te two completely unrelated changes.

horkhe commented 11 years ago

Ok I will move them to another pull request. But thispull request puts ret_specs to a dedicated module so they would need to be accepted in order. First changes with passthrough a func and then this one

eproxus commented 11 years ago

Dependencies between pull requests are fine. I just don't want to pull in a lot of changes in one huge pull request. It's easier to review and discuss them if they are separated.

horkhe commented 11 years ago

@eproxus I created another pull request for ret_spec part. Let's start from it first.

eproxus commented 11 years ago

@horkhe Sure, sound good!

horkhe commented 11 years ago

It's too tied into Hamcrest itself. I'd like Hamcrest to be an optional dependency, not required. This means that some of the Meck API would understand Hamcrest matchers, but not depend on them. This pull request seems to wrap and hide Hamcrest inside Meck. I'd rather integrate with Hamcrest optionally.

Yes and no. Meck introduces its own abstraction for matchers that is meck_matcher. A meck_matcher instance can be created from a predicate function (that will probably be the most widely used case) or from a matcher of a supported 3rd party framework (at the moment only Hamcrest is supported). meck_matcher is the only piece of Meck code that knows about Hamcrest existence. But even though hamcrest per se is optional I put it as a dependency to the Meck rebar.config effectively forcing everybody who takes dependency on Meck pull Hamcrest as well. I admit that that was a bad idea. To resolve that I made two rebar configs: one external that takes no dependencies and will be used by Meck users; and internal test.config that is used by internal Makefile to build and test the Meck itself.

In my opinion, too many modules. meck_matcher and meck_args_matcher could be merged to one for example

Well as I already explained in one of my comments I create them not because I like a lot of modules :) but rather because I like to keep different abstractions separately. For example meck_matcher introduces a matcher abstraction - an entity that encapsulates some criteria and provides a way to verify if some value meets this criteria. Matchers can be created from predicate functions and matchers of supported frameworks. As for meck_args_matcher it is an abstraction that is used to represent an expectation clause arguments where individual parameter may be fully defined - a value, partially defined - a '_' pattern, or conditionally defined - a matcher. In the future the code that generates argument matching code for impostor module will move here. That is why I created all these modules. Yet again not because I have a fetish for large numbers :-).

So this is it. Please let me know what do you think.

And by the way, happy new year!!! :-)

horkhe commented 11 years ago

@eproxus Hi Adam, I left a reply to your comment, please review when you have time.

eproxus commented 11 years ago

Just a note, I'd prefer more, smaller commits with isolated, atomic changes. As it is now, it's a bit hard to follow the development and get an overview of how interdependent changes are. It's also okay with smaller pull request containing clean ups and other minor changes separately. They'll more likely be accepted faster in that case.

horkhe commented 11 years ago

Yep. I did such a humangous pull request in an effort to push more changes to the upstream faster. It is obvious now that that was a biiiiiig mistake, for the effect was reverse. In the future I will do smaller commits/pull requests as you suggested.

eproxus commented 11 years ago

The code looks good. I also want to try out the API a bit manually before the final merge. Will let you know when it's done.

horkhe commented 11 years ago

Glad to hear that :-)

eproxus commented 11 years ago

Seems that the dialyzer plt creation somehow sneaked into the build scripts, making them take longer than 30 secs on Travis CI. Can't see any dependencies on the dialyzer targets in the makefile though, any ideas?

horkhe commented 11 years ago

Well, I made that on purpose to make sure that the code is checked by static analyzer on pull requests. But it seems that on R14 it takes too long to build PLT. As you can see R15 is much faster with this respect. So I should probably remove the dialyzer check from the build.

horkhe commented 11 years ago

@eproxus Have you had a chance to give the API a try?

eproxus commented 11 years ago

Let's remove it for now then.

Yes, I'll merge as soon as the compilation problems are fixed and all travis builds passes. :+1:

horkhe commented 11 years ago

@eproxus Hey Adam, it seems I am finally done with that :)

horkhe commented 11 years ago

@eproxus could you please merge this. I have other changes coming.

horkhe commented 11 years ago

Thanks a lot!

eproxus commented 11 years ago

Np. Forgot to check the build on Travis, but seems the GitHub hooks works now as well.