Skip to content

choice-form/ut_injector

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ut Injector

运行时依赖注入器。本质上它只提供一个全局注册和寻找机制,注入的东西是什么由开发者决定。

实践上多用于注入定义好 behaviour 的模块,并为 test 和其他环境注入不同的实现,避免通过函数参数传参注入导致的 “每层都要带注入参数” 的问题。

安装

ut_injector 加入 mix.exs

def deps do
  [
    {:ut_injector, git: "git@github.com:choice-form/ut_injector.git", tag: "v0.1.0"}
  ]
end

使用

首先推荐把 ut_injector 的 DSL 加入 .formatter.exs

# in .formatter.exs
[
  import_deps: [:ut_injector],
]

在你的 app 中定义 Injector 模块。如果是 umbrella app ,你可能需要定义多个 Injector ,这取决于你是否要进行 app 之间的依赖隔离。

defmodule YourApp.Injector do
  use UtInjector, app: :your_app
end

在 config 文件中注册要注入的东西,每个被注入的东西需要唯一的 key 。所谓被注入的东西由你决定。

下面以 “为 test 其他环境注入不同的模块” 的场景举例:

# in config/config.exs
config :your_app, YourApp.Injector,
  registry: %{
    mod_1: YourApp.Mod1,
    mod_2: YourApp.Mod2
  }

# in config/test.exs
config :your_app, YourApp.Injector,
  registry: %{
    mod_1: YourApp.Mod1Mock,
    mod_2: YourApp.Mod2Mock
  }

可选,为了保证实际模块和 Mock 模块的行为一致,推荐定义 behaviour ,并用 Mox & Hammox 生成测试模块:

# in your_app/lib/your_app/mod_1.ex 中
defmodule YourApp.Mod1Intf do
  @callback some_func() :: :ok
end

defmodule YourApp.Mod1 do
  @behaviour YourApp.Mod1Intf

  @impl true
  def some_func, do: :ok
end

# in test/support/mocks.ex
Hammox.defmock(YourApp.Mod1Mock, for: YourApp.Mod1Intf)

在需要注入依赖的模块中使用。实践中可以为被注入的模块和其测试都 use injector :

defmodule YourApp.TopLevelMod do
  use YourApp.Injector

  # 编译时注入,同样支持 as。这会生成 mod_three/0 的宏
  # 编译时的好处是可以利用 Elixir 的编译时检查,比如函数不存在时警告
  inject_macro :mod_1

  # 运行时注入。这会为生成 mod_1/0 函数,返回值是被注入的东西
  inject_function :mod_2
  # 也可以修改生成的函数名
  inject_function :mod_3, as: :mod_three

  def hello do
    mod_1().some_func()
    mod_2().some_func()
    mod_three().some_func()
  end
end

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages