How can I avoid the "warning: redefining module Foo" when running ExUnit tests multiple times in one process
Asked Answered
A

2

6

I wish to be able to run the ExUnit tests multiple times from within a running process, such as iex.

To do this I have code that looks somewhat like this:

def test do
  # Unload test files
  ["test"]
  |> Mix.Utils.extract_files("*")
  |> Enum.map(&Path.expand/1)
  |> Code.unload_files

  # Reenable tasks
  ~w(loadpaths deps.loadpaths test)
  |> Enum.map(&Mix.Task.reenable/1)

  # Run the test suite
  Mix.Task.run("test", args)

  # Cleanup
  :elixir_config.put(:at_exit, [])
end

This works, but prints the test/my_app/foo_test.exs:1 warning: redefining module FooTest for each module defined in my test files.

I thought that as I had unloaded those files from the :elixir_code_server these warnings would not be raised, but this is not the case.

How might I silence or avoid these warnings without resorting to methods such as silencing stderr?

It seems there is a compiler flag that I can use to suppress these warnings, but there is no clear public API for setting this flag. It seems we can disable these warning messages, there there is no clear API for doing so.

See elixir_compiler:get_opt/1
https://github.com/elixir-lang/elixir/blob/master/lib/elixir/src/elixir_compiler.erl#L8-L13

See elixir_module:check_module_availability/3 where it checks elixir_compiler:get_opt(ignore_module_conflict)
https://github.com/elixir-lang/elixir/blob/master/lib/elixir/src/elixir_module.erl#L408-L418

Airsickness answered 28/4, 2016 at 22:13 Comment(2)
Unloading doesn't help, because loaded modules and defined modules are two different things. If you open fresh console and type Ex <tab> it won't show you ExUnit, because it is not loaded, but it is defined. If you type ExUnit.non_existent_fun it will load the ExUnit and it will be in the shell. I think your best option would be to skip mix and run ExUnit directly. There is an recompile command in iex anyway, so you would only need to start the tests.Brooke
If I run ExUnit directly I still need to handle recompilation of the test files, which still results in the same warning messages. Do you know how to avoid these?Airsickness
D
13

After some trial-and-error storming, this is the solution that works for me:

Code.compiler_options(ignore_module_conflict: true)

Cheers!

Dropwort answered 9/8, 2016 at 12:26 Comment(1)
This is the correct answer, although it should be ignore_module_conflict:true when you need to turn it off temporarily, and false when you want to turn it back on.Stanwinn
R
-1

This might do it:

mix test --no-compile

or in your case, set args to include --no-compile like so:

 # Run the test suite
 Mix.Task.run("test","--no-compile")

NB: I'm not able to test that code for correctness right now so if it's wrong, apologies in advance.

Rustin answered 29/4, 2016 at 12:51 Comment(1)
If modules are not recompiled there's no point in running the tests multiple times as nothing will have changed. I unload the files so that recompilation is triggered the second time.Airsickness

© 2022 - 2024 — McMap. All rights reserved.