I’ve been trying to learn more about GenServer and friends, and getting increasingly obsessive about keeping dependencies as minimal as possible (the ease of which is one of my “new” favorite things about working with Elixir). So when the need arose to generate some unique test data in a project, instead of adding ExMachina (which I have found not nearly as helpful as FactoryBot was in Rails projects), I decided to see what I could do with an Agent.
The code to handle the sequencing was pretty trivial:
defmodule Sequencer do
use Agent
def start_link(_) do
Agent.start_link(fn -> %{} end, name: __MODULE__)
end
def get(id) do
Agent.get_and_update(__MODULE__, fn state ->
{state, Map.update(state, id, 0, fn seq -> seq + 1 end)}
end)
Agent.get(__MODULE__, & &1)
|> Map.fetch!(id)
end
end
And then to use in my test (after adding to supervision tree):
Repo.insert!(%User{email: "test-#{Sequencer.get(:user_email)}@example.com"})
This seems to work, but I haven’t tested very intensely at all. I feel like I must be missing some pitfalls with this approach…
From what I understand, calls to Sequencer will always be processed one at a time, so there’s no chance of a collision as long as the name is unique.
Combining the two Agent operations in a single method was the only vaguely smelly thing, but even there I’m not aware of any problems with that.
Please roast my code.