Home Archives Search Feed


Accessing Private Functions in Elixir

Whlle reading Meck’s code I noticed something very interesting!

Meck is a testing library written in Erlang that recompiles modules replacing the original module with a testing module.

:meck.expect(MyModule, :my_function, fn x -> x + 1 end)

The above code will change the original function called my_function from the module MyModule to behave like the anonymous function that was passed.

This works just fine, but there’s an issue with this approach. Calculating test coverage of a module is much more complicated now that the module can change during the test execution.

To work around this problem Meck applies a very interesting technique:

The problem is that cover doesn’t expose ways to change the coverage data in a simple way like described above.

Meck’s solution is to change covers code during execution to export some specific private functions: https://github.com/eproxus/meck/blob/2c7ba603416e95401500d7e116c5a829cb558665/src/meck_cover.erl#L54-L91

Once Meck can access these privates functions then it’s easy to reconstruct the cover data that needs to be generated at the end!

If we wanted to be more aggressive and expose all private functions from cover, this code should do the job:

{_, binary, _} = :code.get_object_code(:cover)
{:ok, {_, [{_, {_, abstract_code}}]}} = :beam_lib.chunks(binary, [:abstract_code])
{:ok, module, binary} = :compile.forms(abstract_code, [:export_all])
:code.load_binary(module, '', binary)

That’s it! The fact that the Erlang VM allows a module to be changed while executing opens up this kind of clever solution!

Posted on August 3, 2019   #elixir     #meck     #test     #hacks  






Previous post →