I’m trying to use Mox to test a fix to a DateTime bug in my app.
The bug was that I was subtracting 1 from the current hour, which was failing at 00h.
I have a GenServer
managing access tokens. It sends a message to itself every hour (using Process.send_after
) to cleanup expired tokens. Part of this logic uses DateTime
to calculate when the next cleanup should be scheduled. It schedules the first cleanup during init()
.
I want to test that the cleanup code works correctly at 00h, so my first thought was to mock DateTime
and fix the date. DateTime
doesn’t implement a behaviour, so I wrote my own behaviour + implementation that wraps the subset of DateTime
functions I’m using.
The problem I’m having is how to mock this properly. I’m using Mox, and setting up a mock in test_helper.exs
. However, because the Genserver uses the DateTime
in init()
, it tries to call the mock before I can define any expectations.
I tried adding Mox.stub_with
at compile time in support/mocks.ex
, to just forward to the real implementation for now, however then I get an error that Mox.Server
is not started.
Is it possible to use Mox to mock a module when that module is used during application initialization?
Here’s the startup error using stub_with
from the tests:
** (Mix) Could not start application my_app: MyApp.Application.start(:normal, []) returned an error: shutdown: failed to start child: MyApp.TokenServer
** (EXIT) an exception was raised:
** (Mox.UnexpectedCallError) no expectation defined for MyApp.DateTimeMock.utc_now/0 in process #PID<0.259.0> with args []
(mox 0.5.2) lib/mox.ex:693: Mox.__dispatch__/4
(my_app 0.1.0) lib/my_app/token_server.ex:64: MyApp.TokenServer.schedule_cleanup/0
(my_app 0.1.0) lib/my_app/token_server.ex:13: MyApp.TokenServer.init/1
Here’s the error if I try to use stub_with
at compile time:
== Compilation error in file test/support/mocks.ex ==
** (exit) exited in: GenServer.call(Mox.Server, {:add_expectation, #PID<0.172.0>, {MyApp.DateTimeMock, :utc_now, 0}, {0, [], &MyApp.DateTime.utc_now/0}}, 30000)
** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
(elixir 1.10.3) lib/gen_server.ex:1013: GenServer.call/3
lib/mox.ex:547: Mox.add_expectation!/4
lib/mox.ex:476: Mox.stub/3
lib/mox.ex:526: anonymous fn/4 in Mox.stub_with/2
Finally, a bigger question: Any suggestions for alternative ways to test time bugs like this?