diff --git a/lib/ex_unit/lib/ex_unit.ex b/lib/ex_unit/lib/ex_unit.ex index f5b4417dfa0..78daafe81ab 100644 --- a/lib/ex_unit/lib/ex_unit.ex +++ b/lib/ex_unit/lib/ex_unit.ex @@ -350,11 +350,25 @@ defmodule ExUnit do Runs the tests. It is invoked automatically if ExUnit is started via `start/1`. + From Elixir v1.14, it accepts an optional list of modules to run + as part of the suite. This is often used to rerun modules already + loaded in memory. + Returns a map containing the total number of tests, the number of failures, the number of excluded tests and the number of skipped tests. """ - @spec run() :: suite_result() - def run do + @spec run(list(atom)) :: suite_result() + def run(additional_modules \\ []) do + for module <- additional_modules do + module_attributes = module.__info__(:attributes) + + if Keyword.get(module_attributes, :ex_unit_async) do + ExUnit.Server.add_async_module(module) + else + ExUnit.Server.add_sync_module(module) + end + end + _ = ExUnit.Server.modules_loaded() options = persist_defaults(configuration()) ExUnit.Runner.run(options, nil) diff --git a/lib/ex_unit/lib/ex_unit/case.ex b/lib/ex_unit/lib/ex_unit/case.ex index ae63eb3fef3..079c0663cf0 100644 --- a/lib/ex_unit/lib/ex_unit/case.ex +++ b/lib/ex_unit/lib/ex_unit/case.ex @@ -294,6 +294,9 @@ defmodule ExUnit.Case do Enum.each(attributes, &Module.register_attribute(module, &1, accumulate: true)) + persisted_attributes = [:ex_unit_async] + Enum.each(persisted_attributes, &Module.register_attribute(module, &1, persist: true)) + attributes = [ before_compile: ExUnit.Case, after_compile: ExUnit.Case, diff --git a/lib/ex_unit/test/ex_unit_test.exs b/lib/ex_unit/test/ex_unit_test.exs index 24015fbbfdd..e1f22cc5cba 100644 --- a/lib/ex_unit/test/ex_unit_test.exs +++ b/lib/ex_unit/test/ex_unit_test.exs @@ -32,6 +32,52 @@ defmodule ExUnitTest do end) =~ "\n0 failures\n" end + test "supports rerunning given modules" do + defmodule SampleAsyncTest do + use ExUnit.Case, async: true + + test "true" do + assert false + end + end + + defmodule SampleSyncTest do + use ExUnit.Case + + test "true" do + assert false + end + end + + defmodule IgnoreTest do + use ExUnit.Case + + test "true" do + assert false + end + end + + configure_and_reload_on_exit([]) + + assert capture_io(fn -> + assert ExUnit.run() == %{ + failures: 3, + skipped: 0, + total: 3, + excluded: 0 + } + end) =~ "\n3 tests, 3 failures\n" + + assert capture_io(fn -> + assert ExUnit.run([SampleSyncTest, SampleAsyncTest]) == %{ + failures: 2, + skipped: 0, + total: 2, + excluded: 0 + } + end) =~ "\n2 tests, 2 failures\n" + end + test "prints aborted runs on sigquit", config do Process.register(self(), :aborted_on_sigquit) line = __ENV__.line + 5