Mr. SoUndso
Mr. SoUndso

Reputation: 93

elixir test fails with "Reason: already started"

I'm currently working on my first big elixir project and wanted to properly utilize testing this time. However, if I add my Modules to the "normal" supervisor, i cannot start them again with start_supervised! and all tests fail with Reason: already started: #PID<0.144.0>

Here is my code:

(application.ex)

    defmodule Websocks.Application do
  # See https://hexdocs.pm/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application

  def start(_type, _args) do
    children = [
      {Websocks.PoolSupervisor, []},
      {Websocks.PoolHandler, %{}}
      # {Websocks.Worker, arg}
    ]

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: Websocks.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

Some of my tests:

defmodule PoolHandlerTest do
  use ExUnit.Case, async: true
  alias Websocks.PoolHandler
  doctest PoolHandler

  setup do
    start_supervised!({PoolHandler, %{}})
    %{}
  end

  test "adding two pools and checking if they are there" do
    assert PoolHandler.add(:first) == :ok
    assert PoolHandler.add(:second) == :ok
    assert PoolHandler.get_pools() == {:ok,%{:first => nil, :second => nil}}
  end

and the pool handler:

defmodule Websocks.PoolHandler do
  use GenServer

  # Client
  def start_link(default) when is_map(default) do
    GenServer.start_link(__MODULE__, default, name: __MODULE__)
  end

  # Server (callbacks)

  @impl true
  def init(arg) do
    {:ok, arg}
  end
end

(I cut out the stuff i think is not necessary, but the complete code is on github here: github)

Thanks in advance for any help i get!

Upvotes: 1

Views: 1143

Answers (1)

Paweł Obrok
Paweł Obrok

Reputation: 23194

As @Everett mentioned in the comment - your application will already be started for you when you mix test, so there is no need to start your GenServers again. It seems like you're interacting with the global instance in your test, so if that's what you want, then it should just work.

However, if you'd like to start a separate instance just for your test, you need to start an unnamed one. For example, you could add an optional pid argument to your wrapper functions:

defmodule Websocks.PoolHandler do

  # ...

  def add(server \\ __MODULE__, value) do
    GenServer.call(server, {:add, value})
  end

  # ...

end

Then, instead of using using start_supervised! like you do, you can start an unnamed instance in your setup and use it in your tests like so:

setup do
  {:ok, pid} = GenServer.start_link(PoolHandler, %{})
  {:ok, %{handler: pid}}
end

test "adding two pools and checking if they are there", %{handler: handler} do
  PoolHandler.add(handler, :first)
  # ...
end

Upvotes: 4

Related Questions