Skip to content

Instantly share code, notes, and snippets.

@whatyouhide
Created January 7, 2016 22:26
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save whatyouhide/adb5804430550e75e2ab to your computer and use it in GitHub Desktop.
Save whatyouhide/adb5804430550e75e2ab to your computer and use it in GitHub Desktop.
Testing private functions in Elixir
defmodule TestDefp do
defmacro __using__(_) do
quote do
import Kernel, except: [defp: 2]
end
end
# Let's redefine `defp/2` so that if MIX_ENV is `test`, the function will be
# defined with `def/2` instead of `defp/2`.
defmacro defp(fun, body) do
def_macro = if function_exported?(Mix, :env, 0) && apply(Mix, :env, [:test]), do: :def, else: :defp
quote, do: Kernel.unquote(def_macro)(unquote(fun), unquote(body))
end
end
defmodule MyModule do
use TestDefp
defp my_fun() do
:ok
end
end
# Now you can test `MyModule.my_fun/0` when MIX_ENV=test :).
# By the way, strive not to test private functions as it may
# be a sign of code smell. You can always export them into a
# separate module and use `@moduledoc false` or simply make
# them public with `@doc false`.
@cthree
Copy link

cthree commented Mar 23, 2017

Love this but unfortunately it's invasive as you need to change the code under test.

@twajjo
Copy link

twajjo commented May 25, 2018

Excellent gist, but I had to make a small change to get it to work. Within the quote do block, after:

import Kernel, except [defp:2]

You have to import this module (TestDefp) to get the macro to kick in:

import __MODULE__

Without this change, the compiler squawks because defp is undefined after the "use TestDefp" statement in the module to test.
Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment