Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Dependency injection for Elixir. Zero code changes required.

License

NotificationsYou must be signed in to change notification settings

stephanos/rewire

Repository files navigation

Build StatusHex.pm

rewire is adependency injection library.

It keeps your application code completely free from testing concerns.

And you can bring your own mock (mox is recommended).

Installation

Just addrewire to your list of dependencies in mix.exs:

defdepsdo[{:rewire,"~> 0.10",only::test}]end

Usage

Given a module such as this:

# this module has a hard-wired dependency on the `English` moduledefmoduleConversationdo@punctuation"!"defstart(),do:English.greet()<>@punctuationend

If you define amox mockEnglishMock you can rewire the dependency in your unit test:

defmoduleMyTestdouseExUnit.Case,async:trueimportRewire# (1) activate `rewire`importMoxrewireConversation,English:EnglishMock# (2) rewire `English` to `EnglishMock`test"start/0"dostub(EnglishMock,:greet,fn->"g'day"end)assertConversation.start()=="g'day!"# (3) test using the mockendend

This example usesmox, butrewire is mocking library-agnostic.

You can use multiplerewires and multiple overrides:

rewireConversation,English:EnglishMockrewireOnlineConversation,Email:EmailMock,Chat:ChatMock

You can also give the alias a different name usingas:

rewireConversation,English:EnglishMock,as:SmallTalk

Note that therewire acts like analias here in terms of scoping.

Alternatively, you can also limit the scope to a dedicated block:

rewireConversation,English:EnglishMockdo# (1) only rewired inside the blockstub(EnglishMock,:greet,fn->"g'day"end)assertConversation.start()=="g'day!"# (2) test using the mockend

Plus, you can also rewire module attributes.

FAQ

Will it work withasync: true?

Yes! Instead of overriding the module globally - likemeck - it creates acopy for each test.

Does it work withmox?

It works great withmox sincerewire focuses on theinjection and doesn't care about where themock module comes from.rewire andmox are a great pair!

Will that slow down my tests?

Maybe just a little? Conclusive data from a larger code base isn't in yet.

Will test coverage be reported correctly?

Yes!

Will it work with stateful processes?

If the stateful process is startedafter its module has been rewired, it will work fine. However, if the module is startedbefore - like a Phoenix controller - it won't work since it can't be rewired anymore.rewire is best used for unit tests.

Will it work with Erlang modules?

It is not able to rewire Erlang modules - but you can replace Erlang module references in Elixir modules.

How does it deal with nested modules?

Only the dependencies of the rewired module will be replaced. Any modules defined around the rewired module will be ignored. All references of the rewired module to them will be pointing to the original. You're always able to rewire them separately yourself.

How do I stopmix format from adding parentheses aroundrewire?

Add this to your.formatter.exs file:

import_deps: [:rewire]

Why do I need this?

I haven't been happy with the existing tradeoffs of injecting dependencies into Elixir modules that allows me to alter their behavior in my unit tests.

For example, if you don't usemox, the best approach known to me is to pass-in dependencies via a function's parameters:

defmoduleConversationdodefstart(mod\\English),do:mod.greet()end

The downsides to that approach are:

  1. Your application code is now littered with testing concerns.
  2. Navigation in your code editor doesn't work as well.
  3. Searches for usages of the module are more difficult.
  4. The compiler is not able to warn you in casegreet/0 doesn't exist on theEnglish module.

If you usemox for your mocking, there's a slightly better approach:

defmoduleConversationdodefstart(),do:english().greet()defpenglish(),do:Application.get(:myapp,:english,English)end

In this approach we use the app's config to replace a module with amox 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 therewire block to use the generated module instead.

About

Dependency injection for Elixir. Zero code changes required.

Topics

Resources

License

Stars

Watchers

Forks

Languages


[8]ページ先頭

©2009-2025 Movatter.jp