When writing integration tests that depend on the current date/time, it is very handy to be able to freeze
or travel
to specific moment (like e.g. timecop for ruby)
Is there a way to achieve something similar in Elixir/Erlang?
I tried mocking Erlang built-ins :os.timestamp
, :erlang.universaltime
using meck
library, however it fails with :cannot_mock_builtin
.
In principle I could implement my own utility library than would enable easy mocking of current time and then use it everywhere instead of built-in methods; however, some libraries use built-ins, so this is not a viable option (e.g Ecto.Model.Timestamps
, generating inserted_at
and updated_at
values)
I would suggest you implement this via dependency injection. For example (using the new time API in 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
In your tests, you can easily replace the time code:
defmodule ThingTest do use ExUnit.Case test "the time" do assert do_stuff("data", fn -> 123 end) == {"data", 123} end end
Here's the corresponding way to do this in 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()}.
And the test:
-module(thing_tests). -include_lib("eunit/include/eunit.hrl"). do_stuff_test() -> ?assertEqual({"data", 123}, do_stuff("data", fun() -> 123 end).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With