definject v0.1.0 Inject View Source

definject transforms function to accecpt a map where we can inject dependent functions.

definject

use Inject

definject send_welcome_email(user_id) do
  %{email: email} = Repo.get(User, user_id)

  Email.welcome(email)
  |> Mailer.send()
end

becomes

def send_welcome_email(user_id, deps \\ %{}) do
  %{email: email} = (deps[{Repo, :get, 2}] || &Repo.get/2).(User, user_id)

  (deps[{Email, :welcome, 1}] || &Email.welcome/1).(email)
  |> (deps[{Mailer, :send, 1}] || &Mailer.send/1).()
end

mock

Then we can inject mock functions in tests.

test "send_welcome_email" do
  Accounts.send_welcome_email(100, %{
    {Repo, :get, 2} => fn User, 100 -> %User{email: "mr.jechol@gmail.com"} end,
    {Mailer, :send, 1} => fn %Email{to: "mr.jechol@gmail.com", subject: "Welcome"} ->
      Process.send(self(), :email_sent)
    end
  })

  assert_receive :email_sent
end

or more simply if you are not interested in arguments passed in mock

test "send_welcome_email with mock/1" do
  Accounts.send_welcome_email(
    100,
    mock(%{
      &Repo.get/2 => %User{email: "mr.jechol@gmail.com"},
      &Mailer.send/1 => Process.send(self(), :email_sent)
    })
  )

  assert_receive :email_sent
end

strict: false

definject raises if the passed map includes function which is not dependency of the injected function. You can disable this check by adding strict: false.

Accounts.send_welcome_email(100, %{
  {Repo, :get, 2} => fn User, 100 -> %User{email: "mr.jechol@gmail.com"} end,
  {Repo, :all, 1} => fn _ -> [%User{email: "mr.jechol@gmail.com"}] end,
  :strict => false,
})

Link to this section Summary

Link to this section Functions

Link to this macro

definject(head, list)

View Source (macro)