如何使用Meck在Erlang中模拟对象?

时间:2013-05-12 17:32:58

标签: erlang mocking tdd stub meck

好的,我正在使用Meck而且我迷路了。我的第一语言(我已经写了大约7个月)是Ruby,所以我似乎无法将我的大脑包裹在Meck中。我确实得到Ruby嘲笑。希望有人可以帮助我。另外,我只写了一个星期的Erlang。

更新了代码(但嘲讽仍无效)......

我有一个Erlang console_io 提示器模块,如下所示:

    -module(prompter).
    -export([prompt/1, guess/0]).

    prompt(Message) ->
      console_io:gets(Message).

    gets() ->
      {_, [Input]} = io:fread("Enter:  ", "~s"),
      Input.

    guess() ->
      Guess_Input = gets(),
      Guess_List = convert_guess_to_list(Guess_Input).

    convert_guess_to_list(Guess_Input) ->
      re:split(Guess_Input, "", [{return, list}, trim]).

我的测试现在看起来像这样:

    -module(prompter_test).
    -include_lib("eunit/include/eunit.hrl").

    guess_1_test() ->
      meck:new(prompter),
      meck:expect(prompter, gets, fun() -> "aaaa" end),
      ?assertEqual(prompter:guess(), ["a","a","a","a"]),
      ?assert(meck:validate(prompter)),
      meck:unload(prompter).

我得到的错误是:

    Eshell V5.9.3.1  (abort with ^G)
    1> prompter_test: guess_1_test (module 'prompter_test')...*failed*
    in function prompter:guess/0
      called as guess()
    in call from prompter_test:guess_1_test/0 (test/prompter_test.erl, line 10)
    in call from prompter_test:guess_1_test/0
    **error:undef

我想在我的测试中模拟(存根?)获取函数,以便获取将返回“aaaa”,然后当我在get_guess()上断言它应该等于[“a”,“a”,“a”, “一”]。

我该怎么做?

2 个答案:

答案 0 :(得分:11)

有两个问题:

  • prompter模块有两个导出的函数,但您只使用gets模拟其中一个(meck:expect)。默认情况下,Meck会创建一个新模块,包含您明确模拟的功能。您可以使用passthrough选项更改它:

    meck:new(prompter, [passthrough]),
    
  • 当您模拟gets函数时,所有模块前缀的调用(即prompter:gets())都被截获,但Meck无法(还是?)拦截内部调用(例如gets()函数中的guess调用),因此您仍然可以获得函数的未调整版本。没有完全令人满意的方法来避免这种情况。您可以将guess中的来电更改为prompter:gets(),或者您可以将gets移到单独的模块中并模拟它。

答案 1 :(得分:5)

第一行说创建一个新的模拟模块my_library_module

    meck:new(my_library_module),

接下来,我们模拟fib中的函数my_library_module,当传入8时返回21:

    meck:expect(my_library_module, fib, fun(8) -> 21 end),

我们有一些eunit断言来测试我们的模拟函数。 code_under_test:run调用是您想要使用模拟模块替换的函数,而21是函数调用所期望的结果:

    ?assertEqual(21, code_under_test:run(fib, 8)), % Uses my_library_module
    ?assert(meck:validate(my_library_module)),

然后我们卸载模拟的模块:

    meck:unload(my_library_module).

如果您想为模块编写相同的测试,可以写:

my_test() ->
    meck:new(console_io),
    meck:expect(console_io, gets, fun() -> "aaaa" end),
    ?assertEqual(["a", "a", "a", "a"], console_io:get_guess()), % Uses console_io
    ?assert(meck:validate(console_io)),
    meck:unload(console_io).