Elixir的时间旅行和时间冻结

jes*_*nko 20 erlang mocking elixir

在编写依赖于当前日期/时间的集成测试时,能够freezetravel特定时刻(例如rubc的timecop)非常方便

有没有办法在Elixir/Erlang中实现类似的东西?

我试图嘲弄二郎内置插件:os.timestamp,:erlang.universaltime使用meck图书馆,但它失败:cannot_mock_builtin.

原则上我可以实现自己的实用程序库,而不是简单地模拟当前时间,然后在任何地方使用它而不是内置方法; 但是,有些库使用内置函数,因此这不是一个可行的选项(例如Ecto.Model.Timestamps,生成inserted_atupdated_at值)

Ada*_*erg 6

我建议你通过依赖注入实现这个.例如(在Erlang 18中使用新的时间API):

defmodule Thing do
  def do_stuff(data), do: do_stuff(data, &:erlang.system_time/0)
  def do_stuff(data, time), do: {data, time.()}
end
Run Code Online (Sandbox Code Playgroud)

在测试中,您可以轻松替换时间码:

defmodule ThingTest do
  use ExUnit.Case

  test "the time" do
    assert do_stuff("data", fn -> 123 end) == {"data", 123}
  end
end
Run Code Online (Sandbox Code Playgroud)

二郎神

这是在Erlang中执行此操作的相应方法:

-module(thing).
-export([do_stuff/1, do_stuff/2]).

do_stuff(Data) -> do_stuff(Data, fun erlang:system_time/0).

do_stuff(Data, Time) -> {Data, Time()}.
Run Code Online (Sandbox Code Playgroud)

而且测试:

-module(thing_tests).
-include_lib("eunit/include/eunit.hrl").

do_stuff_test() ->
    ?assertEqual({"data", 123}, do_stuff("data", fun() -> 123 end).
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你的回答!但是我不确定这种方法在集成测试的上下文中如何工作,其中 _external_ 库使用 `erlang:system_time`(例如 `Ecto` 用于在插入/更新的行上自动设置时间戳)... (3认同)
  • 是的,你没有运气。没有办法解决这个问题,除非这些库能够对时间进行参数化。我想你唯一的选择是在虚拟机中运行系统并修改 Erlang 之外的时间。 (2认同)