Should I mock a GenServer to prevent database isolation issues?

I’m testing a function that also sends a cast to a GenServer as such;

WebhookDispatcher.dispatch(event, url)

The event is an Ecto struct, stored in a database. The dispatch function enqueues the event and dispatches it asynchronously. After the event has been sent, it’ll be updated in the database with the status result of the webhook.

The issue is the test finishes before the event is dispatched. So as the GenServer is doing its work it will render an Ecto.StaleEntryError. I think that is due to the database isolation for each test or process.

In this test I’m not interested in whether or not the dispatch is successful, I just want the cast to happen and that’s it.

I’ve managed to “solve” the problem by mocking the GenServer and just returning an :ok instead of actually enqueueing anything. Another “solution” was to have the test sleep for 100ms so the process wasn’t killed, but well, you know, sleeping in tests… :sweat_smile:

Is this the right way to solve this issue or are there better ways to do so?

I would probably solve this in one of two ways:

  • If the result of the dispatch is not important for the test: Mock the GenServer
  • If the result is relevant, provide a way to wait for the result. This could for example be a message that is sent back to the dispatching process which could be awaited in your test.
1 Like

Sending any synchronous message to the GenServer will make your test wait until the handle_cast finishes - even just :sys.get_state/1 will do the trick.

2 Likes

@maennchen @al2o3cr

Thanks to you both for your replies. Even though I had the mock set up, I went with :sys.get_state/1 as it saves me from all the extra code having implement a behaviour to be mocked.