Testing Side Processes with Monitoring in Elixir

I recently wrapped up a new project for one of our clients. In that project, we start a supervised GenServer that sends an email and immediately terminates. This process records the email being sent before terminating normally.

We had passing tests but in most test runs we had a big ugly Ecto sandbox warning because the test finished and terminated before the recording that the email was sent. Not great. Below is a simplified version of what that process looks like.

defmodule App.EmailSender do
  use GenServer
  def start_link(), do: ...
  def init(_) do
    {:ok, %{}, {:continue, :deliver}}
  def handle_continue(:deliver, state) do
    # do the delivery
    # record what happened, this is where it explodes in tests
    {:stop, :normal, state}

In order to get around this, I added in a Process.monitor to the PID that just launched.

With the processed monitored, we'll receive a :DOWN message on process termination. We can then assert_receive on that message to let the test process pause just long enough to make sure everything stays green and ERROR free. This works because assert_receive blocks for up to 100ms (before failing) letting the other process send and record without issue.

defmodule App.EmailTest do
  use ExUnit.Case
  alias App.Email
  test "sending an email" do
    email = create_email()
    {:ok, pid} = Email.deliver(email)
    ref = Process.monitor(pid)
    # assert whatever else

    assert_receive {:DOWN, ^ref, :process, _object, :normal}

With this in place for every test that uses that process, we can now make sure the delivery process isn't outpaced by the test process in regards to the Ecto sandbox.

Header photo by Dean Brierley on Unsplash

You've successfully subscribed to SmartLogic Blog
Great! Next, complete checkout for full access to SmartLogic Blog
Welcome back! You've successfully signed in.
Unable to sign you in. Please try again.
Success! Your account is fully activated, you now have access to all content.
Error! Stripe checkout failed.
Success! Your billing info is updated.
Error! Billing info update failed.