@@ -121,6 +121,10 @@ defmodule Mix.Tasks.Test do
121
121
122
122
* `--cover` - runs coverage tool. See "Coverage" section below
123
123
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
+
124
128
* `--exclude` - excludes tests that match the filter. This option may be given
125
129
several times to apply different filters, such as `--exclude ci --exclude slow`
126
130
@@ -494,7 +498,8 @@ defmodule Mix.Tasks.Test do
494
498
warnings_as_errors: :boolean ,
495
499
profile_require: :string ,
496
500
exit_status: :integer ,
497
- repeat_until_failure: :integer
501
+ repeat_until_failure: :integer ,
502
+ dry_run: :boolean
498
503
]
499
504
500
505
@ cover [ output: "cover" , tool: Mix.Tasks.Test.Coverage ]
@@ -623,6 +628,7 @@ defmodule Mix.Tasks.Test do
623
628
624
629
warnings_as_errors? = Keyword . get ( opts , :warnings_as_errors , false )
625
630
exit_status = Keyword . fetch! ( ex_unit_opts , :exit_status )
631
+ dry_run? = Keyword . get ( opts , :dry_run , false )
626
632
627
633
# Prepare and extract all files to require and run
628
634
test_paths = project [ :test_paths ] || default_test_paths ( )
@@ -659,69 +665,115 @@ defmodule Mix.Tasks.Test do
659
665
660
666
warn_files != [ ] && warn_misnamed_test_files ( warn_files )
661
667
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
+ """ )
673
693
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
677
702
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 . ( )
682
730
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 ] ) )
684
737
685
- System . at_exit ( fn _ ->
686
- exit ( { :shutdown , 1 } )
687
- end )
738
+ System . at_exit ( fn _ ->
739
+ exit ( { :shutdown , 1 } )
740
+ end )
688
741
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" )
691
744
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 )
696
749
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 )
701
754
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 )
705
758
706
- true ->
707
- :ok
708
- end
759
+ true ->
760
+ :ok
761
+ end
709
762
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" )
714
767
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" )
717
770
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
722
775
723
- :ok
724
- end
776
+ :ok
725
777
end
726
778
727
779
# 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
847
899
:only_test_ids ,
848
900
:test_location_relative_path ,
849
901
:exit_status ,
850
- :repeat_until_failure
902
+ :repeat_until_failure ,
903
+ :dry_run
851
904
]
852
905
853
906
@ doc false
0 commit comments