eproxus / meck

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

Extended expect syntax and more #73

Closed horkhe closed 12 years ago

horkhe commented 12 years ago

With this patch I would like to suggest the following changes:

  1. Previously sequences of return values could be defined through special sequence and loop functions. This patch introduces an alternative syntax that allows defining return specifications right in the expect function. Consider:

    meck:expect(Mod, f, 1, meck:val(a)), % equivalent to meck:expect(Mod, f, 1, a) ?assertEqual(a, Mod:f(1001)), ?assertEqual(a, Mod:f(1001)),

    meck:expect(Mod, f, 1, meck:seq([a, b])), ?assertEqual(a, Mod:f(1001)), ?assertEqual(b, Mod:f(1001)), ?assertEqual(b, Mod:f(1001)),

    meck:expect(Mod, loop, 1, meck:loop([a, b])), ?assertEqual(a, Mod:loop(1001)), ?assertEqual(b, Mod:loop(1001)), ?assertEqual(a, Mod:loop(1001)),

  2. Previously expectations can be defined either as func-name/arity or as func-name/anon-func. This patch introduces the third way which is defining an expectations through a list of arg pattern/values just like defining an ordiry function but shorter. Consider:

    meck:expect(Mod, f, [{[1, 1], a}, {[1, ''], b}, {['', '_'], c}]), ?assertEqual(a, Mod:f(1, 1)), ?assertEqual(b, Mod:f(1, 2)), ?assertEqual(c, Mod:f(2, 2)).

  3. Combining return specifications and argument patterns you can create quite sophisticated expectations. Consider:

    meck:expect(Mod, f, [{[1, 1], meck:seq([a, b, c])}, {[1, ''], meck:loop([d, e])}, {['', '_'], meck:val(f)}]), ?assertEqual(d, Mod:f(1, 2)), ?assertEqual(f, Mod:f(2, 2)), ?assertEqual(e, Mod:f(1, 2)), ?assertEqual(a, Mod:f(1, 1)), ?assertEqual(d, Mod:f(1, 2)), ?assertEqual(b, Mod:f(1, 1)), ?assertEqual(c, Mod:f(1, 1)), ?assertEqual(f, Mod:f(2, 2)), ?assertEqual(c, Mod:f(1, 1)), ?assertEqual(e, Mod:f(1, 2)), ?assertEqual(c, Mod:f(1, 1)).

  4. Besides internal data structure redesign made in the scope of this patch allows easier introduction of hamcrest patterns into the expectation definition.

Adam, please consider this changes and provide your comments.

horkhe commented 12 years ago

I did rebase and squashed changes to one commit for your convenience.

eproxus commented 12 years ago

I like this, a lot!

horkhe commented 12 years ago

@eproxus, I removed rebar.config and .gitignore changes from the original commit and that whipped out almost all your comments. Fortunately I managed to address all of them anyway. Please take a look.

horkhe commented 12 years ago

@eproxus have you had a chance to take a look at the changes?

eproxus commented 12 years ago

Sorry for the late reply. I'm planning to pull this in ASAP, I'll keep you posted.

horkhe commented 12 years ago

@eproxus just want to let you know that I've got another pull request coming that is based on this one. It will introduce 'honest' mocks that is mocks that allow you to create expectations for exported functions only. That will for example make your unit test fail if a module, mocked in your unit test, was updated to add a new parameter to a function that you have expectations for, hereby detecting the fact that you forgot to update your module and unit test earlier.

travisbot commented 12 years ago

This pull request passes (merged 12c2dea0 into beb8d14e).

eproxus commented 12 years ago

Also, you've managed to make creation of expect functions faster. :+1:

Before:

1> meck_performance_test:run(10000).
                Min     Max     Med     Avg
expect/3        1246    3435    1370    1409
expect/3+args   1939    7537    2253    2547
expect/4        2291    5497    2446    2474
expect/4+args   2797    6436    2950    3002

                Min     Max     Med     Avg
normal          8       682     9       10
normal_args     8       1652    9       10
shortcut        0       21      1       1
shortcut_args   0       36      1       1
shortcut_opaque 8       1545    9       11

                Min     Max     Med     Avg
called          19      135     20      21

After:

1> meck_performance_test:run(10000).
                Min     Max     Med     Avg
expect/3        1195    3732    1275    1289
expect/3+args   1825    5115    1980    2012
expect/4        2019    5271    2142    2187
expect/4+args   2385    6972    2539    2607

                Min     Max     Med     Avg
normal          9       648     10      10
normal_args     9       1591    10      11
shortcut        9       276     9       10
shortcut_args   9       304     10      10
shortcut_opaque 9       4777    10      12

                Min     Max     Med     Avg
called          19      75      20      22

Note however that the "shortcut" versions of the expects (e.g. meck:expect(M, F, 1, ok)) are slower (they were previously compiled into the mock module itself (there are a few lines of coverage missing around 689 and 710). It's not terribly important right now, and I also realized that with the ArgsPattern structure there will be even more opportunities for code generation.

travisbot commented 12 years ago

This pull request passes (merged 92b8ae37 into beb8d14e).

horkhe commented 12 years ago

Glad to hear about the performance though it was not intentional. I addressed the most of your comments as good as I could manage at such late hour :)

travisbot commented 12 years ago

This pull request passes (merged fa0eb68b into beb8d14e).

horkhe commented 12 years ago

Seems like this is it :)

travisbot commented 12 years ago

This pull request passes (merged de63a05a into beb8d14e).

horkhe commented 12 years ago

@eproxus I do not want to sound pushy but is it possible to speed up code inspection a little? I have got 3 more pull requests coming.

eproxus commented 12 years ago

Sorry for the incredibly long lag on my responses. I've now merged this into develop so we can let it brew for a while. Nice work! :-)

horkhe commented 12 years ago

Thanks! ...to be continued :-)