`mix test` launches entire app

Background

I have an application and I am trying to test some of its components. To do this, I am using mix test which is causing me trouble.

Application

I noticed that mix test first launches the entire app before running any tests, even though no tests require the full app to be launched. This is causing me issues because some of the tests require processes to be registered in the Registry, but the tests fail because the ids of those processes are already started.

# registering with key {__MODUDLE, 1}
{:ok, _pid} = Worker.start_link({1, %{registry: RegistryMock}})

{:error, {:already_started, #PID<0.176.0>}}

Question

  1. Is this normal behaviour in mix test?
  2. How do I tell mix.test to not launch a the entire app? Ideally it would only run the code I tell it to.

Yes, this behaviour is as expected and documented. You can use a command line switch to avoid the start:

  • --no-start - does not start applications after compilation

Update mix.exs file and add a line under def project.... like so:

  def project do
    [app: :my_app,
     #...
     aliases: [test: "test --no-start"],
     #...
  end
3 Likes

I can use --no-start, but if I do so, all my tests fail because Mox isn’t launched either.
Is there a way to fix this? I didn’t find anything in the documentation :frowning_face:

I don’t want the application to be launched, but I do want the testing libraries to be launched. How am I supposed to test if --no-start doesn’t launch my testing dependencies? :cry:

I would have the application start as per usual but start new and unnamed versions of any process you want to test in the test itself.

It’s useful not to hard-code process names for this reason :slight_smile:

This is also nice because it allows your to run tests concurrently even if they both leverage the same kind of process because there no longer is a dependancy on global mutable state. It’ll save you from having to do lots of teardown code to ensure the global state is reset between each test too

1 Like

You will have to launch it explicitly by doing Application.ensure_all_started(:mox) and so on for every dependency.

In my opinion, not starting your application in your tests because you want to manually start a process with the same name is somewhat a bad practice. Instead, I would make sure my API allows processes to be started with a custom name, so you do:

Worker.start_link(:my_name_during_test, ...)

And I tend to use the test name as the name of the process itself:

test "my test", config do
  Worker.start_link(config.test, ...)
end

This works nicely if you are starting the process from setup too.

4 Likes

How would you start an unamed process when using Registry? (which requires you to give processes a name?)

I would give the process a different name for that test

test "my test" do
  {:ok, pid} = MyProcess.start_link(name: :my_unique_test_name)
end

This requires you to take the name in your start_link function and pass it to (for example) GenServer.start_link.

1 Like