Thanks for confirming and referencing the past discussion! 100% agree that `async: :per_test | :per_module | true | false` is the way to go 👍 Most people can then switch to it with a global search & replace.
I looked into the current ExUnit implementation and came up with several design directions. ## Current implementation: 1. register test modules 1. ExUnit.Case calls ExUnit.Server.add_sync_module in after_compile <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/case.ex#L528-L532> 2. ExUnit.Server.add_async_module <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/server.ex#L12> 2. mix test 1. Mix.Tasks.Test <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/mix/lib/mix/tasks/test.ex#L1> match test files 2. Mix.Compilers.Test.require_and_run/4 <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/mix/lib/mix/compilers/test.ex#L25> require and run matched test files 3. run tests 1. ExUnit.run/0 <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit.ex#L380> 2. ExUnit.Runner.run/2 <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/runner.ex#L8> 3. ExUnit.Runner.async_loop/3 <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/runner.ex#L95> 4. ExUnit.Server.take_async_modules/1 5. ExUnit.Runner.spawn_modules/2 <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/runner.ex#L154-L165> 6. spawn_monitor -> ExUnit.Runner.run_module/2 <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/runner.ex#L214> 7. ExUnit.EventManager 1. module_started 2. test_started 3. test_finished 4. module_finished 8. ExUnit.Runner.run_module/3 <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/runner.ex#L278> 1. run_setup_all 2. spawn_monitor -> module.__ex_unit__(:setup_all, test_module.tags) 9. ExUnit.Runner.run_tests/3 <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/runner.ex#L345> 10. ExUnit.Runner.run_test/3 <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/runner.ex#L356> 11. ExUnit.Runner.spawn_test/3 <https://github.com/elixir-lang/elixir/blob/d34b708d53a808be8ed569b263797bdf6ca3d6e0/lib/ex_unit/lib/ex_unit/runner.ex#L374> 1. spawn_test_monitor/4 2. receive_test_reply/4 3. exec_on_exit/3 ## possible design directions: 1. registration 1. save async test cases separately from async modules 2. save async_per_test modules & async_per_module modules 2. taking 1. return async test cases from ExUnit.Server.take_async_per_test_cases/1 2. return async_per_test modules from ExUnit.Server.take_async_modules(:per_test, count) return async_per_module modules from ExUnit.Server.take_async_modules(:per_module, count) 3. return both modules from ExUnit.Server.take_async_modules/1 3. running 1. spawn_tests/3 before spawn_modules/2 2. spawn_tests/3 inside spawn_modules/2 if it's a per_test async module I'd prefer 1.2 + 2.2 + 3.1: - save async_per_test modules & async_per_module modules - return async_per_test modules from ExUnit.Server.take_async_modules(:per_test, count) - spawn_tests/3 before spawn_modules/2 What do you think? Best, Yiming On Sunday, September 3, 2023 at 10:48:11 PM UTC+8 José Valim wrote: > Yes, it is desirable and it has come up in the past: > https://github.com/elixir-lang/elixir/pull/11949#issuecomment-1177262901 > > Although I think async: :per_module is what most people want, since the > tests in the same module tend to access the same resource, opting-in for it > to be per test will be welcome tho. > > On Thu, Aug 31, 2023 at 4:57 PM Yiming Chen <dsds...@gmail.com> wrote: > >> Currently, ExUnit's `async: true` option would run test cases in this >> module synchronously, >> but only run this module asynchronously along with other `async: true` >> modules. >> >> This is to propose we add an option for ExUnit to run asynchronously by >> test cases. >> >> # Background >> 1. Async by module was a surprise >> >> My initial understanding of `async: true` is async by cases, instead of >> modules. It's a bit surprising the behavior is later. >> >> 2. Async by module would behave more like synchronous tests as a module >> gets more test cases >> >> As we grow our libraries/apps, a test module will have more and more test >> cases. >> It's tedious to break them into separate modules to speed up the test >> suite run. >> And breaking them into modules has the cost of making related tests >> further from each other. >> >> # Benefits >> 1. speed up test suite runs for libraries, apps almost effortlessly >> 2. more accurate `async: xxx seconds, sync: yyy seconds` metrics >> >> # Caveats >> >> 1. Async by test cases may not run faster than async by modules: >> - managing these test cases has a cost on its own >> - communicating these test cases between ExUnit Server and Runner has >> costs as well >> 2. backward compatibility with current `async: true` behavior >> >> some libs or apps may rely on the async by module behavior. >> we should still allow user to use `async: ture` by default, >> and make async by test cases an easily opt-in feature. >> >> 3. Async by test cases may complex the ExUnit implementation even further >> >> # Potential solution >> >> I looked into current ExUnit implementation a little bit >> I think `async by test cases` is doable, but I don't have a concrete >> solution yet >> >> A initial idea is to: >> 1. instead of saving modules in ExUnit Server, we save test cases (mfa) >> in ExUnit Server >> 2. when Runner asks for more async tests, ExUnit Server returns test >> cases (and also modules) for Runner >> >> This seems to be a huge change, >> so I'd like to know if this feature is desirable/feasible from the core >> team's PoV before I dig more into it. >> >> Best, >> Yiming >> >> -- >> You received this message because you are subscribed to the Google Groups >> "elixir-lang-core" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to elixir-lang-co...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/elixir-lang-core/51ad9575-71b9-4afe-8996-1dd9e2aea7b8n%40googlegroups.com >> >> <https://groups.google.com/d/msgid/elixir-lang-core/51ad9575-71b9-4afe-8996-1dd9e2aea7b8n%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> > -- You received this message because you are subscribed to the Google Groups "elixir-lang-core" group. To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-core+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/3ca6d5aa-a073-4144-98c2-0a2d5bcc86f5n%40googlegroups.com.