Upload
xiaozhe-wang
View
738
Download
0
Embed Size (px)
Citation preview
ERLYMOCK TUTORIAL
By chaoslawful
What’s ErlyMock?
A mocking framework for Erlang Mock any method in any modules Various features:
Argument verification Call order verification
Divergence: Sheyll’s: http://erlymock-site.sourceforge.net Nialscorva’s: https://github.com/nialscorva/
erlymock
Looking down from 30,000ft high Sheyll’s version:
M = em:new(),
em:strict(M, module, function, [arg, em:any()], {return, ok}),
em:stub(M, module, function2, [1, 2, 3], {function, fun (_) -> throw(myerror) end}),
% replaying phase
em:replay(M),
% test
?assertMatches(ok, module:function(arg, anything)),
?assertThrow(myerror, module:function2(1, 2, 3)),
em:verify(M).
Looking down from 30,000ft high
Nialscorva version:
erlymock:start(),erlymock:strict(module, function, [arg, '_'], [{return, ok}]),erlymock:stub(module, function2, [1, 2, 3], [{throw, myerror}]),
% initializeerlymock:replay(),
% test?assertMatches(ok, module:function(arg, anything)),?assertThrow(myerror, module:function2(1, 2, 3)),erlymock:verify().
ErlyMock(sheyll’s) Funcs
em:new/0 – Create new mock expectation instance (gen_fsm proc) em:strict/4,5 – Strict call expectation
Strict calls must occur once for each, and in the order of declarations. em:strict/4 mocked func always return atom ‘ok’ em:strict/5 can specify return value with:
{return, V} – Mocked func return value V {function, F} – Mocked func call function F, and use its return value as return value
em:stub/4,5 – Stub call expectation Stub calls can occur any times, and in any order. Mocked func return value can be specified as above.
em:replay/1 – Finish expectation programming phase, start replaying phase Must be called before actual test code and after expectation declarataions.
em:verify/1 – Verify expectations, and destroy mock instance Must be called after test code.
em:any/0 – Return wildcard argument verifier em:nothing/2 – Demand no funcs in the specified module can be called
ErlyMock(nialscorva’s) Funcs erlymock:start/0 – Start mock service (gen_server proc) erlymock:strict/3,4 – Strict call expectation
Strict calls must occur once for each, and in the order of declarations. erlymock:strict/3 mocked funcs always return atom ‘ok’ erlymock:strict/4 can specify return value with (put in a list):
{return, V} – Mocked func return value V {throw, V} – Mocked func call erlang:throw/1 with reason V {exit, V} – Mocked func call erlang:exit/1 with reason V {error, V} – Mocked func call erlang:error/1 with reason V {function, F} – Mocked func call function F, and use its return value as return value
erlymock:replay/0 – Finish expectation programming, start replaying phase Must be called before actual test code and after expectation declarataions.
erlymock:verify/0,1 – Verify expectations, and destroy mock instance Must be called after test code. erlymock:verify/1 can specify timeout for verification process.
ErlyMock(nialscorva’s) Funcs, cont. erlymock:stub/3,4 – Stub call expectation
Stub calls can occur any times, and in any order. Mocked func return value can be specified as above. Can retrict minimum and maximum invocation times of
mocked func with options: {min_invocations, Count} – Specify min invocation times,
default to 0. {max_invocations, Count} – Specify max invocation times,
default to infinity. erlymock:o_o/3,4 – Out of order call expectation
Out of order calls are simply stub calls with min_invocation=max_invocation=1, i.e. call exactly once in any order.
Mocked func return value can be specified as above.
Mock example – Missile Launcher Two layer:
launch_console – Interact with missile operator launcher – Called by console, control missile
hardware Need test launch_console:launch/0, it must comply
to the following restrictions: Must call launcher:confirm/0 first If launcher:confirm/0 return false, nothing to do If launcher:confirm/0 return true, call launcher:launch/2 with fixed coordinate
Time must be retrieved through launcher:time/0
Mock example - Missile Launcher
Mocking test cases:mock_test1() ->
M = em:new(),
em:stub(M, launcher, time, [], {function, fun () -> Old = case get(mock_time) of undefined -> 0; V -> V end, put(mock_time, Old+1), Old end}),
em:stub(M, launcher, launch, [em:any(), em:any()], {function, fun ()->throw(should_not_happen) end}),
em:strict(M, launcher, confirm, [], {return, false}),
em:replay(M),
launch_console:launch(),
em:verify(M).
mock_test2() ->
Lat = 33.8, Lon = 45.0,
M = em:new(),
em:stub(M, launcher, time, [], {function, fun () -> Old = case get(mock_time) of undefined -> 0; V -> V end, put(mock_time, Old+1), Old end}),
em:strict(M, launcher, confirm, [], {return, true}),
em:strict(M, launcher, launch, [Lat, Lon]),
em:replay(M),
launch_console:launch(),
em:verify(M).
Commons between impls
Use beam code hot swapping mechanism to implement module mocking. See compile:forms/1, code:purge/1, code:delete/1 and erlang:load_module/2
Note: Mocking must happened for entire module, restricted by
this impl method. Mocking partial funcs in a module is netiher possible nor desirable.
Can’t mock the same module in parallel running test cases.
Mocked funcs are generated on the fly in memory, according to declared expectations. See erl_syntax module
Sheyll’s compare to Nialscorva’s
Pros Can recover coverage data after mocking finished Shortter module name ;-) Support multiple expectation instance (can parallel run test cases if
using different mock module) Implemented in gen_fsm, cleaner than Nialscorva’s With ‘nothing’ expectation With ‘any’ arg verifier, express wildcard matching in cleaner way
Cons Can’t restrict stub call min/max invocation times No out of order call expectation (due to above reason) No express way to specify throw/exit/error return value No built-in TCP server mocking support (can be done with self-
connected socket pair) No short-cut wildcard arg verifier ‘_’ (but also without its ambiguity) Use maven instead of rebar as building tools, not very erly…
Personal thoughts
Neither impl are good enough… For now, recommend Sheyll’s impl prior
to Nialscorva’s We can contribute our efforts to make
Sheyll’s impl better, it’s not so hard. Sheyll’s impl: 641 lines Nialscorva’s impl: 843 lines
Q&A
That’s all, folks!