README.md

rewire
===

[![Build Status](https://travis-ci.org/stephanos/rewire.svg?branch=master)](https://travis-ci.org/stephanos/rewire)
[![Hex.pm](https://img.shields.io/hexpm/v/rewire.svg)](https://hex.pm/packages/rewire)

Keep your code free from dependency injection and mocking concerns by using `rewire` in your unit tests to stub out any module dependencies.

## Example

```elixir
defmodule Conversation do
  def start(), do: English.greet()              # the dependency is hard-wired
end
```

You can rewire the dependency with a mock, using `mox` for example:

```elixir
defmodule MyTest do
  use ExUnit.Case
  use Rewire
  import Mox

  rewire Conversation, English: Mock            # acts as an alias to the rewired module

  test "greet" do
    stub(Mock, :greet, fn -> "bonjour" end)
    assert Conversation.start() == "bonjour"    # this uses Mock now!
  end
end
```

Alternatively, you can also rewire a module on a test-by-test basis:

```elixir
defmodule MyTest do
  use ExUnit.Case
  use Rewire
  import Mox

  test "greet" do
    rewire Conversation, English: Mock do       # within the block it is rewired
      stub(Mock, :greet, fn -> "bonjour" end)
      assert Conversation.start() == "bonjour"  # this uses Mock now!
    end
  end
end
```

You can also give the alias a different name using `as`:

```elixir
  rewire Conversation, English: Mock, as: SmallTalk
```

## FAQ

**Why?**

I haven't been happy with the existing tradeoffs of making a module with dependencies easily unit testable.

If you don't use `mox`, the best approach known to me is to pass-in dependencies via a function's parameters:

```elixir
defmodule Conversation do
  def start(mod \\ English), do: mod.greet()
end
```

But this will (1) litter your code with testing concerns, (2) make navigation in your editor harder, (3) searches for usages of the module more difficult and (4) make it impossible for the compiler to warn you in case `greet/0` doesn't exist on the `English` module

If you use `mox`, there's a slightly better approach:

```elixir
defmodule Conversation do
  def start(), do: english().greet()
  defp english(), do: Application.get(:myapp, :english, English)
end
```

In this approach we use the app's config to replace a module with a `mox` mock during testing. This is a little better in my opinion, but still comes with most of the disadvantages described above.

**Witchcraft! How does this work??**

Simply put, `rewire` will create a copy of the module to rewire under a new name, replacing all hard-coded module references that should be changed in the process. Plus, it rewrites the test code in the `rewire` block to use the generated module instead.

**Will that slow down my tests?**

Possibly just a little? Conclusive data isn't in yet.

**Does it work with `mox`?**

It works great with [mox](https://github.com/dashbitco/mox) since `rewire` doesn't care about where the replacement module comes from. `rewire` and `mox` are a great pair!