Подтвердить что ты не робот

Путешествие во времени и время замерзания в Эликсире

При написании тестов интеграции, которые зависят от текущей даты/времени, очень удобно иметь возможность freeze или travel до определенного момента (например, timecop для рубина)

Есть ли способ добиться чего-то подобного в Elixir/Erlang?

Я пробовал издеваться над встроенными инсталляциями Erlang :os.timestamp, :erlang.universaltime с помощью библиотеки meck, но с ошибкой :cannot_mock_builtin.

В принципе, я мог бы реализовать свою собственную библиотеку утилиты, чем позволял бы легко высмеивать текущее время, а затем использовать ее везде, а не встроенные методы; однако некоторые библиотеки используют встроенные модули, поэтому это не жизнеспособный вариант (например, Ecto.Model.Timestamps, генерирующий значения inserted_at и updated_at)

4b9b3361

Ответ 1

Elixir

Я предлагаю вам реализовать это путем инъекции зависимостей. Например (используя новый API времени в Erlang 18):

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

В ваших тестах вы можете легко заменить временной код:

defmodule ThingTest do
  use ExUnit.Case

  test "the time" do
    assert do_stuff("data", fn -> 123 end) == {"data", 123}
  end
end

Erlang

Здесь соответствующий способ сделать это в 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()}.

И тест:

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

do_stuff_test() ->
    ?assertEqual({"data", 123}, do_stuff("data", fun() -> 123 end).