I wanted to share
rewire with you, a dependency injection library I’ve been working on over the last few weeks. It aims to keep your production code free from testing concerns, works with async tests and any mock.
Given a module such as this:
# this module has a hard-wired dependency on the `English` module
defmodule Conversation do
def start(), do: English.greet()
If you define a
EnglishMock you can rewire the dependency in your unit test:
defmodule MyTest do
use Rewire # (1) activate `rewire`
rewire Conversation, English: EnglishMock # (2) rewire `English` to `EnglishMock`
test "start/0" do
stub(EnglishMock, :greet, fn -> "g'day" end)
assert Conversation.start() == "g'day" # (3) test using the mock
Check out all the details at:
And let me know what you think!
Looks nice except one thing - why use
use instead just plain
import? It should work without problems.
That’s cool! I’ve been struggling in how to organise a callback mechanism (eg. after creating the record send an email and also generate a receipt), but keep it decoupled enough to be able to test well.
Rewire could help here! Will check it out.
Very interesting. Since it works by aliasing, does that mean it can only be used for unit testing the module directly? For example, if I have a module called
Conversation.start/0, there’s no way to rewire the
English reference, is that right?
From what I see in the code - yes, it works only for modules called directly.
you’re absolutely right! I originally had some compiler hooks in there to update the module attributes but never went back to
require after I realized I didn’t need that.
Just updated the docs and shipped a new version to reflect that.
actually, you could stack them:
rewire Conversation, English: EnglishMock
rewire Discord, Conversation: Conversation
You can find a working test case here: https://github.com/stephanos/rewire/blob/master/test/rewire_alias_test.exs#L16
But I’m not sure whether that’s a good testing etiquette. Reaching deeply into module’s might be a smell, depending on the use case.