jechol
Definject - Unobtrusive Dependency Injector for Elixir
Hello,
I just published version 1.1 of definject. It aims to make dependency injection unobtrusive.
import Definject
definject send_welcome_email(user_id) do
%{email: email} = Repo.get(User, user_id)
welcome_email(to: email)
|> Mailer.send()
end
is expanded into (simplified for understanding)
def send_welcome_email(user_id, deps \\ %{}) do
%{email: email} = Map.get(deps, &Repo.get/2, &Repo.get/2).(User, user_id)
welcome_email(to: email)
|> Map.get(deps, &Mailer.send/1, &Mailer.send/1).()
end
Then, you can inject mock functions and modules in tests.
test "send_welcome_email" do
Accounts.send_welcome_email(100, %{
Repo => MockRepo,
&Mailer.send/1 => fn %Email{to: "user100@gmail.com", subject: "Welcome"} ->
Process.send(self(), :email_sent)
end
})
assert_receive :email_sent
end
definject does not require you to modify function arguments or body. Instead, you just need to replace def with definject . It also allows injecting different mocks to each function. It also does not limit using :async option as mocks are contained in each test function.
You can find definject here:
Thanks!
Most Liked
ityonemo
Typically with Mox you sub out the module name at compile time and at test time you bind in functions. This cleverly uses registry, $callers and $ancestors (I think) to make sure tests get isolated mocks.
With definject, the function is majorly fiddled with (basically rewritten) so that you don’t have to do that compile-time module substitution.
I would be worried that definject is more brittle and has more corner cases, but it’s the sort of thing where if it works for you it’ll work really well.







