@@ -121,6 +121,10 @@ defmodule Mix.Tasks.Test do
121121
122122    * `--cover` - runs coverage tool. See "Coverage" section below 
123123
124+     * `--dry-run` - prints which tests would be run based on current options, 
125+       but does not actually run any tests. This combines with all other options 
126+       like `--stale`, `--only`, `--exclude`, etc. 
127+ 
124128    * `--exclude` - excludes tests that match the filter. This option may be given 
125129      several times to apply different filters, such as `--exclude ci --exclude slow` 
126130
@@ -494,7 +498,8 @@ defmodule Mix.Tasks.Test do
494498    warnings_as_errors:  :boolean , 
495499    profile_require:  :string , 
496500    exit_status:  :integer , 
497-     repeat_until_failure:  :integer 
501+     repeat_until_failure:  :integer , 
502+     dry_run:  :boolean 
498503  ] 
499504
500505  @ cover  [ output:  "cover" ,  tool:  Mix.Tasks.Test.Coverage ] 
@@ -623,6 +628,7 @@ defmodule Mix.Tasks.Test do
623628
624629    warnings_as_errors?  =  Keyword . get ( opts ,  :warnings_as_errors ,  false ) 
625630    exit_status  =  Keyword . fetch! ( ex_unit_opts ,  :exit_status ) 
631+     dry_run?  =  Keyword . get ( opts ,  :dry_run ,  false ) 
626632
627633    # Prepare and extract all files to require and run 
628634    test_paths  =  project [ :test_paths ]  ||  default_test_paths ( ) 
@@ -659,69 +665,115 @@ defmodule Mix.Tasks.Test do
659665
660666    warn_files  !=  [ ]  &&  warn_misnamed_test_files ( warn_files ) 
661667
662-     try  do 
663-       Enum . each ( test_paths ,  & require_test_helper ( shell ,  & 1 ) ) 
664-       # test_opts always wins because those are given via args 
665-       ExUnit . configure ( ex_unit_opts  |>  merge_helper_opts ( )  |>  Keyword . merge ( test_opts ) ) 
666-       CT . require_and_run ( matched_test_files ,  test_paths ,  test_elixirc_options ,  opts ) 
667-     catch 
668-       kind ,  reason  -> 
669-         # Also mark the whole suite as failed 
670-         file  =  Keyword . fetch! ( opts ,  :failures_manifest_path ) 
671-         ExUnit.Filters . fail_all! ( file ) 
672-         :erlang . raise ( kind ,  reason ,  __STACKTRACE__ ) 
668+     if  dry_run?  do 
669+       do_dry_run ( matched_test_files ) 
670+     else 
671+       do_wet_run ( 
672+         shell , 
673+         cover , 
674+         test_paths , 
675+         files , 
676+         matched_test_files , 
677+         test_opts , 
678+         test_elixirc_options , 
679+         ex_unit_opts , 
680+         warnings_as_errors? , 
681+         exit_status , 
682+         opts 
683+       ) 
684+     end 
685+   end 
686+ 
687+   defp  do_dry_run ( matched_test_files )  do 
688+     if  matched_test_files  ==  [ ]  do 
689+       Mix . shell ( ) . info ( """ 
690+       -- DRY RUN -- 
691+       No tests would run 
692+       """ ) 
673693    else 
674-       { :ok ,  % { excluded:  excluded ,  failures:  failures ,  warnings?:  warnings? ,  total:  total } }  -> 
675-         Mix . shell ( shell ) 
676-         cover  &&  cover . ( ) 
694+       Mix . shell ( ) . info ( """ 
695+       -- DRY RUN -- 
696+       The following test files would be run: 
697+ 
698+       #{ Enum . join ( matched_test_files ,  "\n " ) }  
699+       """ ) 
700+     end 
701+   end 
677702
678-         cond  do 
679-           warnings_as_errors?  and  warnings?  and  failures  ==  0  -> 
680-             message  = 
681-               "\n ERROR! Test suite aborted after successful execution due to warnings while using the --warnings-as-errors option" 
703+   defp  do_wet_run ( 
704+          shell , 
705+          cover , 
706+          test_paths , 
707+          files , 
708+          matched_test_files , 
709+          test_opts , 
710+          test_elixirc_options , 
711+          ex_unit_opts , 
712+          warnings_as_errors? , 
713+          exit_status , 
714+          opts 
715+        )  do 
716+     Enum . each ( test_paths ,  & require_test_helper ( shell ,  & 1 ) ) 
717+     # test_opts always wins because those are given via args 
718+     ExUnit . configure ( ex_unit_opts  |>  merge_helper_opts ( )  |>  Keyword . merge ( test_opts ) ) 
719+     CT . require_and_run ( matched_test_files ,  test_paths ,  test_elixirc_options ,  opts ) 
720+   catch 
721+     kind ,  reason  -> 
722+       # Also mark the whole suite as failed 
723+       file  =  Keyword . fetch! ( opts ,  :failures_manifest_path ) 
724+       ExUnit.Filters . fail_all! ( file ) 
725+       :erlang . raise ( kind ,  reason ,  __STACKTRACE__ ) 
726+   else 
727+     { :ok ,  % { excluded:  excluded ,  failures:  failures ,  warnings?:  warnings? ,  total:  total } }  -> 
728+       Mix . shell ( shell ) 
729+       cover  &&  cover . ( ) 
682730
683-             IO . puts ( :stderr ,  IO.ANSI . format ( [ :red ,  message ] ) ) 
731+       cond  do 
732+         warnings_as_errors?  and  warnings?  and  failures  ==  0  -> 
733+           message  = 
734+             "\n ERROR! Test suite aborted after successful execution due to warnings while using the --warnings-as-errors option" 
735+ 
736+           IO . puts ( :stderr ,  IO.ANSI . format ( [ :red ,  message ] ) ) 
684737
685-              System . at_exit ( fn  _  -> 
686-                exit ( { :shutdown ,  1 } ) 
687-              end ) 
738+           System . at_exit ( fn  _  -> 
739+             exit ( { :shutdown ,  1 } ) 
740+           end ) 
688741
689-            failures  >  0  and  opts [ :raise ]  -> 
690-              raise_with_shell ( shell ,  "\" mix test\"  failed" ) 
742+         failures  >  0  and  opts [ :raise ]  -> 
743+           raise_with_shell ( shell ,  "\" mix test\"  failed" ) 
691744
692-            warnings_as_errors?  and  warnings?  and  failures  >  0  -> 
693-              System . at_exit ( fn  _  -> 
694-                exit ( { :shutdown ,  exit_status  +  1 } ) 
695-              end ) 
745+         warnings_as_errors?  and  warnings?  and  failures  >  0  -> 
746+           System . at_exit ( fn  _  -> 
747+             exit ( { :shutdown ,  exit_status  +  1 } ) 
748+           end ) 
696749
697-            failures  >  0  -> 
698-              System . at_exit ( fn  _  -> 
699-                exit ( { :shutdown ,  exit_status } ) 
700-              end ) 
750+         failures  >  0  -> 
751+           System . at_exit ( fn  _  -> 
752+             exit ( { :shutdown ,  exit_status } ) 
753+           end ) 
701754
702-            excluded  ==  total  and  Keyword . has_key? ( opts ,  :only )  -> 
703-              message  =  "The --only option was given to \" mix test\"  but no test was executed" 
704-              raise_or_error_at_exit ( shell ,  message ,  opts ) 
755+         excluded  ==  total  and  Keyword . has_key? ( opts ,  :only )  -> 
756+           message  =  "The --only option was given to \" mix test\"  but no test was executed" 
757+           raise_or_error_at_exit ( shell ,  message ,  opts ) 
705758
706-            true  -> 
707-              :ok 
708-          end 
759+         true  -> 
760+           :ok 
761+       end 
709762
710-        :noop  -> 
711-          cond  do 
712-            opts [ :stale ]  -> 
713-              Mix . shell ( ) . info ( "No stale tests" ) 
763+     :noop  -> 
764+       cond  do 
765+         opts [ :stale ]  -> 
766+           Mix . shell ( ) . info ( "No stale tests" ) 
714767
715-            opts [ :failed ]  ||  files  ==  [ ]  -> 
716-              Mix . shell ( ) . info ( "There are no tests to run" ) 
768+         opts [ :failed ]  ||  files  ==  [ ]  -> 
769+           Mix . shell ( ) . info ( "There are no tests to run" ) 
717770
718-            true  -> 
719-              message  =  "Paths given to \" mix test\"  did not match any directory/file: " 
720-              raise_or_error_at_exit ( shell ,  message  <>  Enum . join ( files ,  ", " ) ,  opts ) 
721-          end 
771+         true  -> 
772+           message  =  "Paths given to \" mix test\"  did not match any directory/file: " 
773+           raise_or_error_at_exit ( shell ,  message  <>  Enum . join ( files ,  ", " ) ,  opts ) 
774+       end 
722775
723-         :ok 
724-     end 
776+       :ok 
725777  end 
726778
727779  # similar to Mix.Utils.extract_files/2, but returns a list of directly included test files, 
@@ -847,7 +899,8 @@ defmodule Mix.Tasks.Test do
847899    :only_test_ids , 
848900    :test_location_relative_path , 
849901    :exit_status , 
850-     :repeat_until_failure 
902+     :repeat_until_failure , 
903+     :dry_run 
851904  ] 
852905
853906  @ doc  false 
0 commit comments