【问题标题】:How to mock objects in Erlang using Meck?如何使用 Meck 在 Erlang 中模拟对象?
【发布时间】:2013-05-06 18:52:52
【问题描述】:

好的,我正在使用 Meck,但我迷路了。我的第一语言(我已经写了大约 7 个月了)是 Ruby,所以我似乎还无法将我的大脑包裹在 Meck mocking 上。我确实得到了 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

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

我该怎么做?

【问题讨论】:

    标签: erlang mocking tdd stub meck


    【解决方案1】:

    有两个问题:

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

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

    【讨论】:

    • 非常感谢!我尝试在调用中将模块名称添加到函数中(“将猜测中的调用更改为提示器:gets()”)。不幸的是,这并没有奏效。因此,我最终将 gets() 提取到它自己的单独模块中,然后我可以按照 kjw0188 的说明进行模拟。
    【解决方案2】:

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

        meck:new(my_library_module),
    

    接下来,我们模拟my_library_module中的函数fib,在传入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).
    

    【讨论】:

    • 非常感谢!我现在完全明白了。但是,测试仍然没有通过。我用我的新代码/测试和我得到的错误更新了上面的问题。希望你能帮帮我。
    • meck:validate/1 在上面的例子中实际上做了什么?我做不出来
    • 还有另一个答案可以回答你的问题:stackoverflow.com/questions/43279705/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-09
    • 1970-01-01
    相关资源
    最近更新 更多