5
votes

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

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. - tkowal
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? - lpil

2 Answers

10
votes

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

Code.compiler_options(ignore_module_conflict: true)

Cheers!

-1
votes

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.