@@ -181,6 +181,9 @@ defmodule Mix.Tasks.Test do
181
181
* `--no-elixir-version-check` - does not check the Elixir version from `mix.exs`
182
182
* `--no-start` - does not start applications after compilation
183
183
* `--only` - runs only tests that match the filter
184
+ * `--partitions` - sets the amount of partitions to split tests in. This option
185
+ requires the `MIX_TEST_PARTITION` environment variable to be set. See the
186
+ "OS Processes Partitioning" section for more information
184
187
* `--preload-modules` - preloads all modules defined in applications
185
188
* `--raise` - raises if the test suite failed
186
189
* `--seed` - seeds the random number generator used to randomize the order of tests;
@@ -189,12 +192,26 @@ defmodule Mix.Tasks.Test do
189
192
Automatically sets `--trace` and `--preload-modules`
190
193
* `--stale` - runs only tests which reference modules that changed since the
191
194
last time tests were ran with `--stale`. You can read more about this option
192
- in the "Stale " section below
195
+ in the "The --stale option " section below
193
196
* `--timeout` - sets the timeout for the tests
194
197
* `--trace` - runs tests with detailed reporting. Automatically sets `--max-cases` to `1`.
195
198
Note that in trace mode test timeouts will be ignored as timeout is set to `:infinity`
196
199
197
- See `ExUnit.configure/1` for more information on configuration options.
200
+ ## Configuration
201
+
202
+ These configurations can be set in the `def project` section of your `mix.exs:
203
+
204
+ * `:test_paths` - list of paths containing test files. Defaults to
205
+ `["test"]` if the `test` directory exists; otherwise, it defaults to `[]`.
206
+ It is expected that all test paths contain a `test_helper.exs` file
207
+
208
+ * `:test_pattern` - a pattern to load test files. Defaults to `*_test.exs`
209
+
210
+ * `:warn_test_pattern` - a pattern to match potentially misnamed test files
211
+ and display a warning. Defaults to `*_test.ex`
212
+
213
+ * `:test_coverage` - a set of options to be passed down to the coverage
214
+ mechanism
198
215
199
216
## Filters
200
217
@@ -251,20 +268,6 @@ defmodule Mix.Tasks.Test do
251
268
If a given line starts a `describe` block, that line filter runs all tests in it.
252
269
Otherwise, it runs the closest test on or before the given line number.
253
270
254
- ## Configuration
255
-
256
- * `:test_paths` - list of paths containing test files. Defaults to
257
- `["test"]` if the `test` directory exists; otherwise, it defaults to `[]`.
258
- It is expected that all test paths contain a `test_helper.exs` file
259
-
260
- * `:test_pattern` - a pattern to load test files. Defaults to `*_test.exs`
261
-
262
- * `:warn_test_pattern` - a pattern to match potentially misnamed test files
263
- and display a warning. Defaults to `*_test.ex`
264
-
265
- * `:test_coverage` - a set of options to be passed down to the coverage
266
- mechanism
267
-
268
271
## Coverage
269
272
270
273
The `:test_coverage` configuration accepts the following options:
@@ -293,9 +296,35 @@ defmodule Mix.Tasks.Test do
293
296
It must return either `nil` or an anonymous function of zero arity that will
294
297
be run after the test suite is done.
295
298
296
- ## "Stale"
299
+ ## OS Processes Partitioning
300
+
301
+ While ExUnit supports the ability to run tests concurrently within the same
302
+ Elixir instance, it is not always possible to run all tests concurrently. For
303
+ example, some tests may rely on global resources.
304
+
305
+ For this reason, `mix test` all supports partitioning the test files across
306
+ different Elixir instances. This is done by setting the `--partitions` option
307
+ to an integer, with the number of partitions, and setting the `MIX_TEST_PARTITION`
308
+ environment variable to control which test partition that particular instance
309
+ is running. This can be also be useful if you want to distribute testing across
310
+ multiple machines.
311
+
312
+ For example, to split a test suite into 4 partitions and run them, you would
313
+ use the following commands:
297
314
298
- The `--stale` command line option attempts to run only those test files which
315
+ MIX_TEST_PARTITION=1 mix test --partitions 4
316
+ MIX_TEST_PARTITION=2 mix test --partitions 4
317
+ MIX_TEST_PARTITION=3 mix test --partitions 4
318
+ MIX_TEST_PARTITION=4 mix test --partitions 4
319
+
320
+ The test files are sorted and distributed in a round-robin fashion. Note the
321
+ partition itself is given as an environment variable so it can be accessed in
322
+ configuration files and test scripts. For example, it can be used to setup a
323
+ different database instance per partition in `config/test.exs`.
324
+
325
+ ## The --stale option
326
+
327
+ The `--stale` command line option attempts to run only the test files which
299
328
reference modules that have changed since the last time you ran this task with
300
329
`--stale`.
301
330
@@ -304,6 +333,9 @@ defmodule Mix.Tasks.Test do
304
333
references (and any modules those modules reference, recursively) were modified
305
334
since the last run with `--stale`. A test file is also marked "stale" if it has
306
335
been changed since the last run with `--stale`.
336
+
337
+ The `--stale` option is extremely useful for software iteration, allowing you to
338
+ run only the relevant tests as you perform changes to the codebase.
307
339
"""
308
340
309
341
@ switches [
@@ -329,6 +361,7 @@ defmodule Mix.Tasks.Test do
329
361
listen_on_stdin: :boolean ,
330
362
formatter: :keep ,
331
363
slowest: :integer ,
364
+ partitions: :integer ,
332
365
preload_modules: :boolean
333
366
]
334
367
@@ -441,6 +474,7 @@ defmodule Mix.Tasks.Test do
441
474
test_files
442
475
|> Mix.Utils . extract_files ( test_pattern )
443
476
|> filter_to_allowed_files ( allowed_files )
477
+ |> filter_by_partition ( opts )
444
478
445
479
display_warn_test_pattern ( test_files , test_pattern , matched_test_files , warn_test_pattern )
446
480
@@ -642,6 +676,33 @@ defmodule Mix.Tasks.Test do
642
676
Enum . filter ( matched_test_files , & MapSet . member? ( allowed_files , Path . expand ( & 1 ) ) )
643
677
end
644
678
679
+ defp filter_by_partition ( files , opts ) do
680
+ if total = opts [ :partitions ] do
681
+ partition = System . get_env ( "MIX_TEST_PARTITION" )
682
+
683
+ case partition && Integer . parse ( partition ) do
684
+ { partition , "" } when partition in 1 .. total ->
685
+ partition = partition - 1
686
+
687
+ # We sort the files because Path.wildcard does not guarantee
688
+ # ordering, so different OSes could return a different order,
689
+ # meaning run across OSes on different partitions could run
690
+ # duplicate files.
691
+ for { file , index } <- Enum . with_index ( Enum . sort ( files ) ) ,
692
+ rem ( index , total ) == partition ,
693
+ do: file
694
+
695
+ _ ->
696
+ Mix . raise (
697
+ "The MIX_TEST_PARTITION environment variable must be set to an integer between " <>
698
+ "1..#{ total } when the --partitions option is set, got: #{ inspect ( partition ) } "
699
+ )
700
+ end
701
+ else
702
+ files
703
+ end
704
+ end
705
+
645
706
defp color_opts ( opts ) do
646
707
case Keyword . fetch ( opts , :color ) do
647
708
{ :ok , enabled? } ->
0 commit comments