How to compile rebar3 dependencies with TEST macro defined?

Hello!

I’m working on an Erlang library application that uses a C library to connect to a proprietary remote service. I wrote the NIF wrapper and everything works fine. In order to test it, I need to mock the calls into the NIF module. Unfortunately meck doesn’t support mocking NIFs, so I work around by adding code like this in all places where the NIF is called:

-ifdef(TEST).
-define(API, mock_module).
-else.
-define(API, nif_module).
-endif.

and I use ?API:call to actually use the module. I wanted to avoid dynamic dispatch here because this NIF might be called thousands of times per second (we haven’t got to load testing yet). It works great.

However, when I want to use this Erlang library from a different Erlang application as a dependency, this trick doesn’t work. rebar3 as test compile fetches and compiles all dependencies without defining the TEST macro, so the test code calls into the NIF module and I’d like to avoid this. Is there a way to compile dependencies with the TEST macro defined? Maybe I should mock the dependency Erlang application, but that’s somewhat complicated.

OTOH - did you run rebar3 clean --all before compilation? Source files haven’t changed so they won’t be recompiled automatically.

I did an rm -fr _build before compilation :slight_smile:

Hmm, here it says that dependencies are always compiles using prod profile. I don’t know what’s the exact reason for it.

You can use overrides to achieve wanted behavior:

{overrides,
    [{add, <dep_name>, [
        {erl_opts, [{d,'TEST'}]}]
    }]
    }.

This is almost good. The problem is that rebar3 seems to compile the dependencies only once and makes a symlink from other profiles (I mean the compiled beam files are in _build/default/lib/<dependency>/ebin and the paths used in the test or prod profiles are symlinks, _build/test/lib/<dependency>/ebin is the same directory as _build/prod/lib/<dependency>/ebin), so I cannot have two beam files for the same module, but with different erl_opts. So if I do a rebar3 compile, then a rebar3 as test shell, I get the non-TEST compiled module in the shell. But the CI pipeline does clean builds for both testing and for generating the release, so it just might work. Thanks again!

1 Like