【问题标题】:Define a constant module in elixir在 Elixir 中定义一个常量模块
【发布时间】:2015-09-30 19:07:51
【问题描述】:

我想创建一些可变的边界模块。理想情况下,结果看起来像任何其他模块,但行为可以在编译时或在配置文件中设置。我想我正在寻找类似在 erlang 中定义的东西

假设我有一个 SystemClock 模块和一个 DummyClock 元组模块。理想情况下,时钟模块是配置文件中选择的上述两个模块之一。

config/test.ex

define(Clock, {DummyClock, 12345678})

稍后

Clock.now
# => 12345678

config/prod.ex

define(Clock, SystemClock)

稍后

Clock.now
# => 32145687

【问题讨论】:

  • 因为在 Erlang 中定义的价值非常类似于 C/C++ 中的#define。那就是它基本上是字符串替换。

标签: testing mocking elixir


【解决方案1】:

我认为最简单的方法是使用配置和Application.get_env/2

config/test.exs

config :my_application, clock: DummyClock

config/dev.exsconfig/prod.exs

config :my_application, clock: RealClock

在使用时钟的代码中

defp clock, do: Application.get_env(:my_application, :clock)

def my_function(arg1, arg2) do
  now = clock.now
  # ...
end

【讨论】:

【解决方案2】:

我用过很多次的一个选项是Meck,也就是you can get/read about here。对于您的示例,我们可能会写如下内容:

test "something that depends on Clock calls Clock.now" do
  :meck.new(Clock, [])
  :meck.expect(Clock, :now, fn -> 12345678 end)

  # we expect that the module under test is getting it's result from Clock
  assert ModuleUnderTest.execute  == 12345678
end

Meck 在测试期间动态替换模块的功能,而不是重新编译代码以获得 :test 行为。

这里其他 cmets 中引用的讨论指出了一些不使用 mocking 的原因;是的,您必须牺牲某些东西(顺序测试和 José 对您的测试代码的看法),但作为交换,您可以在棘手的情况下大大简化测试代码。

【讨论】:

    猜你喜欢
    • 2016-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-04
    • 1970-01-01
    • 2019-05-01
    相关资源
    最近更新 更多