eproxus/meck

Passthrough'd function call can't seem to call a mocked function

Closed this issue · 2 comments

If I have a module that is mocked with the passthrough option, and call an unmocked function, which in turn calls a function that I have attempted to set up an expectation for, it appears the original implementation of the mocked function is called, instead.

Unfortunately I'm not skilled enough at Erlang yet to quite figure out what's going on in the meck code, but I have an example Elixir application showcasing the issue, if that might be helpful for figuring out the issue?

https://github.com/jordan0day/meck_weirdness

In essence, there's just one module with two functions: do_it and some_function. do_it calls some_function.

in test/meck_weirdness_test.exs, you can see in the second that I've set up the mock with the passthrough option (via new/2), and then set up an expectation on the function some_function. The mocked version of some_function is not called, though.

In the third test, I'm using new/1, and then using meck's passthrough/1 function to call the original implementation of the do_it function. I've again mocked some_function using expect, but again the original implementation of some_function is being executed.

Let me know if there's any more details I can provide to help debug this!

I believe this is the case of Meck only having power to modify exported function calls (see #106, for example). The implementation of Meck replaces a module in the Erlang VM with a mocked one, but internal calls are direct jumps in the byte code of the same module. To avoid this, you need to call the function with a fully qualified call (module + function name):

  def do_it do
    IO.puts "In do_it"
    result = MeckWeirdness.some_function("a", "b")
    IO.puts "result: #{inspect result}\n"

    result
  end

It's a very rare case that you need to mock a function call from the same module, and in such cases it is almost always possible to refactor the program to use more than one module (perhaps too much responsibility is in one module?). Or, you are mocking at the wrong place.

Ah, bummer, I was afraid of that. I looked through the past issues but somehow missed #106. I totally agree with your assessment that usually that code probably belongs in a different module, anyway. Thanks for a taking a look at it!