minitest-suite 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 14315494c6d4e85d5f6a754070add34121f58dac9499820f1a3936496c71a38e
4
- data.tar.gz: 7c5e5da23030fb27f8f4b3a2db983f918ca62a8aae89527bb28b0c78cceafb77
3
+ metadata.gz: f4c6431daa7d510ea5146c3b8b417c77847f7f3f5d5a64b331248b8e3299e8e5
4
+ data.tar.gz: e8c90ad9b02cda9467c7eee661ce47d539e2b055be68219e09965b23890238ae
5
5
  SHA512:
6
- metadata.gz: a4ce626b86e3c40b8091078c9210f18a714d7c67cc1cdcbcbea77f240ca7dfa4014c3280d286cfaaf84cbb44679fa9c7527e4ebe2692a216fc9cbdaf81d468c6
7
- data.tar.gz: db057fcf019dbf786c7755b300df0c226cd6cf27c54c5572765ccdd3c0e6731558097efd34ed962a0c30fa248bce45064c6ae4d086dc99625274f08c612978a2
6
+ metadata.gz: 9554fb2541a0be0b30c454841a667640194ee5c0f1ce9e53f1c4a5c5bc0ea0c37fb6d39e9ccc9803c8161aed0651b4833ce23c26f39c1ca6916cf7a101f220ed
7
+ data.tar.gz: 419c7a9f46e85b059dffcefea7170527c274fdcf38533f0d41b197480284253390239ee9d7d076223bdb46f763281e70a25c9daa2e5331455b666726adf8ca12
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ # 0.0.2
2
+
3
+ - Adds Minitest::Suite.order= for specifying initial suite order
4
+ - Adds MINITEST_SUITE_ONLY and MINITEST_SUITE_EXCEPT options
5
+
1
6
  # 0.0.1
2
7
 
3
8
  - initial release
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- minitest-suite (0.0.1)
4
+ minitest-suite (0.0.2)
5
5
  minitest
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -5,8 +5,8 @@ The minitest-suite gem modifies the way
5
5
  `Minitest::Test` subclasses are run by allowing you to organize them into
6
6
  sub-suites or groups.
7
7
 
8
- This can be handy when you want to (usually for performance reasons) want to run
9
- one logical grouping of tests at a time before moving onto the next.
8
+ This can be handy when you want to (usually for performance reasons) run
9
+ one logical grouping of tests at a time before moving onto the next group.
10
10
 
11
11
  ## Using minitest-suite
12
12
 
@@ -26,8 +26,8 @@ require "minitest/suite"
26
26
 
27
27
  ### Declaring suites
28
28
 
29
- To associate a test class, just pass a suite name to `suite` in the body of each
30
- test class:
29
+ Just pass a suite name to `suite` in the class body of each
30
+ test to group that test with others of the same named suite:
31
31
 
32
32
  ```ruby
33
33
  class SweetTest < Minitest::Test
@@ -47,9 +47,9 @@ of those suites will be shuffled.
47
47
  For example, suppose you have 4 test classes, two fruits and two vegetables:
48
48
 
49
49
  ```ruby
50
- class Pumpkin < Minitest::Test
50
+ class Broccoli < Minitest::Test
51
51
  suite :veggie
52
- def test_it() = puts("🎃")
52
+ def test_it() = puts("🥦")
53
53
  end
54
54
 
55
55
  class Pear < Minitest::Test
@@ -77,17 +77,71 @@ the order will still be randomized):
77
77
 
78
78
  🍐
79
79
  .🍎
80
- .🎃
80
+ .🥦
81
81
  .🌶
82
82
  .
83
83
  ```
84
84
 
85
85
  To wit, the above strategy will ensure you'd never see this test order:
86
- 🍐,🌶,🍎,🎃.
86
+ 🍐,🌶,🍎,🥦.
87
87
 
88
88
  Looking for more? Check out this repo's [example
89
89
  test](/example/test/sweet_test.rb).
90
90
 
91
+ ### Configuration
92
+
93
+ Since you're going to the trouble of organizing your tests into logical suites,
94
+ you may as well have a little additional control over which suites run and in
95
+ what order. Below are a few handy things you can do once you're set up.
96
+
97
+ #### Fix the ordering that suites run in
98
+
99
+ A very sensible strategy is to optimize the speed of your feedback loop by run
100
+ your fastest tests first so your tests can fail fast.
101
+
102
+ As a typical example, suppose you want to run your pure Ruby unit tests, then
103
+ your Rails model tests, then your other (presumably slower) integration tests.
104
+ Near the top of your test helper, before your tests have started running, set
105
+ the order like this:
106
+
107
+ ```ruby
108
+ Minitest::Suite.order = [:unit, :model]
109
+ ```
110
+
111
+ With this set, any test classes that call `suite :unit` will be shuffled and run
112
+ first, then any tests with `suite :model`, and then the rest of your suites and
113
+ tests.
114
+
115
+ (Fail-fast behavior is available for Minitest via the [minitest-fail-fast
116
+ gem](https://github.com/teoljungberg/minitest-fail-fast) or the [Rails test
117
+ runner](https://guides.rubyonrails.org/testing.html#the-rails-test-runner)'s
118
+ `-f` flag.)
119
+
120
+ #### Filter to run only certain test suites
121
+
122
+ If you want to run only tests belonging to a certain suite or set of suites,
123
+ just set the environment variable `MINITEST_SUITE_ONLY` to a comma-delimited
124
+ string of suite names to run:
125
+
126
+ ```
127
+ $ MINITEST_SUITE_ONLY="unit,model" bin/rake test
128
+ ```
129
+
130
+ When using this option, note that test classes that _don't_ call `suite` **will
131
+ not be run**.
132
+
133
+ #### Run all tests except certain suites
134
+
135
+ If there's a suite of tests you don't want to run, set the environment variable
136
+ `MINITEST_SUITE_EXCEPT` to a comma-delimited string of suite names to skip:
137
+
138
+ ```
139
+ $ MINITEST_SUITE_EXCEPT="integration,browser" bin/rake test
140
+ ```
141
+
142
+ When using this option, note that test classes that _don't_ call `suite` **will
143
+ be run**.
144
+
91
145
  ## Code of Conduct
92
146
 
93
147
  This project follows Test Double's [code of
data/example/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- minitest-suite (0.0.1)
4
+ minitest-suite (0.0.2)
5
5
  minitest
6
6
 
7
7
  GEM
@@ -0,0 +1,65 @@
1
+ def assert_good_only_run(suites, bad)
2
+ unless bad.empty?
3
+ raise <<~MSG
4
+ Expected to only run #{suites.inspect}, but these suites ran and shouldn't have:
5
+
6
+ #{bad.join("\n")}
7
+ MSG
8
+ end
9
+ end
10
+
11
+ module Exe
12
+ def self.cution(exe)
13
+ @executions ||= []
14
+ @executions << exe
15
+ end
16
+
17
+ def self.cutions
18
+ @executions || []
19
+ end
20
+ end
21
+
22
+ at_exit do
23
+ if (setting = ENV["MINITEST_SUITE_ONLY"])
24
+ suites = setting.gsub(/\s+/, "").split(",").map(&:to_sym)
25
+ bad = Exe.cutions.reject { |exe| suites.include?(exe) }
26
+ assert_good_only_run(suites, bad)
27
+ elsif (setting = ENV["MINITEST_SUITE_EXCEPT"])
28
+ suites = setting.gsub(/\s+/, "").split(",").map(&:to_sym)
29
+ bad = Exe.cutions.select { |exe| suites.include?(exe) }
30
+ assert_good_only_run(suites, bad)
31
+ end
32
+ end
33
+
34
+ require "minitest/suite"
35
+ require "minitest/autorun"
36
+
37
+ class Test1 < Minitest::Test
38
+ suite :suite1
39
+
40
+ def test_it
41
+ Exe.cution :suite1
42
+ end
43
+ end
44
+
45
+ class Test2 < Minitest::Test
46
+ suite :suite2
47
+
48
+ def test_it
49
+ Exe.cution :suite2
50
+ end
51
+ end
52
+
53
+ class Test3 < Minitest::Test
54
+ suite :suite3
55
+
56
+ def test_it
57
+ Exe.cution :suite3
58
+ end
59
+ end
60
+
61
+ class Test4 < Minitest::Test
62
+ def test_it
63
+ Exe.cution :unsuitened
64
+ end
65
+ end
@@ -0,0 +1,113 @@
1
+ module Exe
2
+ def self.cution(exe)
3
+ @executions ||= []
4
+ @executions << exe
5
+ end
6
+
7
+ def self.cutions
8
+ @executions || []
9
+ end
10
+ end
11
+
12
+ at_exit do
13
+ expected = Minitest::Suite.order
14
+ expected_index = 0
15
+
16
+ Exe.cutions.each.with_index do |suite, actual_index|
17
+ finished_suites = expected_index == 0 ? [] : expected[0..(expected_index - 1)]
18
+
19
+ if finished_suites.include?(suite)
20
+ raise <<~MSG
21
+ Ensuring order #{expected.inspect} but #{suite.inspect} test was just run
22
+ out of order. Actual execution order:
23
+
24
+ #{Exe.cutions.map(&:inspect).join("\n")}
25
+ MSG
26
+ elsif suite == expected[expected_index]
27
+ # cool
28
+ else
29
+ expected_index += 1
30
+ end
31
+ end
32
+ end
33
+
34
+ require "minitest/suite"
35
+ require "minitest/autorun"
36
+
37
+ Minitest::Suite.order = ENV["ORDER"].split(",").map(&:to_sym)
38
+
39
+ class Test1 < Minitest::Test
40
+ suite :suite1
41
+
42
+ def test_it
43
+ Exe.cution :suite1
44
+ end
45
+ end
46
+
47
+ class Test2 < Minitest::Test
48
+ suite :suite2
49
+
50
+ def test_it
51
+ Exe.cution :suite2
52
+ end
53
+ end
54
+
55
+ class Test3 < Minitest::Test
56
+ suite :suite3
57
+
58
+ def test_it
59
+ Exe.cution :suite3
60
+ end
61
+ end
62
+
63
+ class Test4 < Minitest::Test
64
+ def test_it
65
+ Exe.cution :unsuitened
66
+ end
67
+ end
68
+
69
+ class Test5 < Minitest::Test
70
+ suite :suite1
71
+
72
+ def test_it
73
+ Exe.cution :suite1
74
+ end
75
+ end
76
+
77
+ class Test6 < Minitest::Test
78
+ suite :suite2
79
+
80
+ def test_it
81
+ Exe.cution :suite2
82
+ end
83
+ end
84
+
85
+ class Test7 < Minitest::Test
86
+ suite :suite3
87
+
88
+ def test_it
89
+ Exe.cution :suite3
90
+ end
91
+ end
92
+
93
+ class Test8 < Minitest::Test
94
+ def test_it
95
+ Exe.cution :unsuitened
96
+ end
97
+ end
98
+
99
+ class Test9 < Minitest::Test
100
+ suite :suite1
101
+
102
+ def test_it
103
+ Exe.cution :suite1
104
+ end
105
+ end
106
+
107
+ class Test10 < Minitest::Test
108
+ suite :suite2
109
+
110
+ def test_it
111
+ Exe.cution :suite2
112
+ end
113
+ end
@@ -15,10 +15,10 @@ at_exit do
15
15
  raise "Expected each suite to be run contiguously, but was not. Actual suite execution order was: #{suite_order}"
16
16
  end
17
17
 
18
- puts "Run order:"
19
- executions.each.with_index do |execution, i|
20
- puts "#{i + 1}. #{execution[:suite]}: #{execution[:class]}##{execution[:method]}"
21
- end
18
+ # puts "Run order:"
19
+ # executions.each.with_index do |execution, i|
20
+ # puts "#{i + 2}. #{execution[:suite]}: #{execution[:class]}##{execution[:method]}"
21
+ # end
22
22
  end
23
23
 
24
24
  require "minitest/suite"
@@ -52,23 +52,3 @@ CLASS_COUNT.times do |i|
52
52
  end
53
53
  })
54
54
  end
55
-
56
- class Pumpkin < Minitest::Test
57
- suite :veggie
58
- def test_it() = puts("🎃")
59
- end
60
-
61
- class Pear < Minitest::Test
62
- suite :fruit
63
- def test_it() = puts("🍐")
64
- end
65
-
66
- class Pepper < Minitest::Test
67
- suite :veggie
68
- def test_it() = puts("🌶")
69
- end
70
-
71
- class Apple < Minitest::Test
72
- suite :fruit
73
- def test_it() = puts("🍎")
74
- end
@@ -1,35 +1,69 @@
1
- require_relative "suite/version"
2
1
  require "minitest"
2
+ require_relative "suite/version"
3
3
 
4
4
  module Minitest
5
5
  module Suite
6
6
  class Error < StandardError; end
7
+ Registration = Struct.new(:suite, :test, keyword_init: true)
7
8
 
8
9
  def self.register(suite_name:, test_class:)
9
- raise Error.new("suite_name must be a Symbol") unless suite_name.is_a?(Symbol)
10
- raise Error.new("test_class must be a Minitest::Test") unless test_class.ancestors.include?(Minitest::Test)
11
- if (conflicting_suite_name = (suites.keys - [suite_name]).find { |suite_name| suites[suite_name].include?(test_class) })
12
- raise Error.new("#{test_class.name || "Class"} is already registered to the #{conflicting_suite_name.inspect} suite")
10
+ if !suite_name.is_a?(Symbol)
11
+ raise Error.new("suite_name must be a Symbol")
12
+ elsif !test_class.ancestors.include?(Minitest::Test)
13
+ raise Error.new("test_class must be a Minitest::Test")
14
+ elsif (conflict = registrations.find { |r| r.test == test_class && r.suite != suite_name })
15
+ raise Error.new("#{conflict.test.name || "Class"} is already registered to the #{conflict.suite.inspect} suite")
16
+ elsif registrations.none? { |r| r.test == test_class && r.suite == suite_name }
17
+ registrations << Registration.new(suite: suite_name, test: test_class)
18
+ end
19
+ end
20
+
21
+ def self.order=(suite_order)
22
+ if !suite_order.is_a?(Array) ||
23
+ suite_order.any? { |suite| !suite.is_a?(Symbol) }
24
+ raise Error.new("Minitest::Suite.order must be an array of Symbol suite names")
25
+ else
26
+ @@suite_order = suite_order.uniq
13
27
  end
14
- suites[suite_name] = (suites[suite_name] + [test_class]).uniq
15
28
  end
16
29
 
17
- def self.suites
18
- Thread.current[:minitest_suites] || reset
30
+ def self.order
31
+ @@suite_order ||= []
32
+ end
33
+
34
+ def self.registrations
35
+ @@registrations ||= reset
19
36
  end
20
37
 
21
38
  def self.reset
22
- Thread.current[:minitest_suites] = Hash.new { [] }
39
+ @@registrations = []
40
+ end
41
+
42
+ def self.filter_runnables(runnables)
43
+ if (only = ENV["MINITEST_SUITE_ONLY"])
44
+ suites = only.gsub(/\s+/, "").split(",").map(&:to_sym)
45
+ selected_tests = registrations.select { |r| suites.include?(r.suite) }
46
+ .map(&:test)
47
+ runnables.select { |r| selected_tests.include?(r) }
48
+ elsif (except = ENV["MINITEST_SUITE_EXCEPT"])
49
+ suites = except.gsub(/\s+/, "").split(",").map(&:to_sym)
50
+ excepted_tests = registrations.select { |r| suites.include?(r.suite) }
51
+ .map(&:test)
52
+ runnables.reject { |r| excepted_tests.include?(r) }
53
+ else
54
+ runnables
55
+ end
23
56
  end
24
57
 
25
58
  class PartialArrayProxy < Array
26
59
  def shuffle
27
- suites = (Suite.suites.keys + [:unsuitened]).shuffle
60
+ filtered = Suite.registrations.select { |r| include?(r.test) }
61
+ suites = Suite.order | (filtered.map(&:suite).uniq + [:__unsuitened]).shuffle
28
62
  suites.flat_map { |suite|
29
- if suite == :unsuitened
30
- (self - Suite.suites.values.flatten).shuffle
63
+ if suite == :__unsuitened
64
+ (self - filtered.map(&:test)).shuffle
31
65
  else
32
- Suite.suites[suite].shuffle
66
+ filtered.select { |r| r.suite == suite }.map(&:test).shuffle
33
67
  end
34
68
  }
35
69
  end
@@ -52,8 +86,13 @@ module Minitest
52
86
  class << self
53
87
  undef_method :runnables
54
88
  define_method :runnables do
55
- return @@runnables if @@runnables.is_a?(Minitest::Suite::PartialArrayProxy)
56
- @@runnables = Minitest::Suite::PartialArrayProxy.new(@@runnables)
89
+ filtered = Minitest::Suite.filter_runnables(@@runnables)
90
+ if @@runnables.is_a?(Minitest::Suite::PartialArrayProxy) &&
91
+ filtered == @runnables
92
+ @@runnables
93
+ else
94
+ @@runnables = Minitest::Suite::PartialArrayProxy.new(filtered)
95
+ end
57
96
  end
58
97
  end
59
98
  end
@@ -1,5 +1,5 @@
1
1
  module Minitest
2
2
  module Suite
3
- VERSION = "0.0.1"
3
+ VERSION = "0.0.2"
4
4
  end
5
5
  end
data/script/test CHANGED
@@ -3,5 +3,23 @@
3
3
  set -ex
4
4
 
5
5
  bundle exec rake
6
+
6
7
  cd example
7
- bundle exec rake
8
+
9
+ bundle exec ruby test/suite_shuffle_test.rb
10
+
11
+ bundle exec ruby test/suite_filter_test.rb
12
+ MINITEST_SUITE_ONLY="suite1" bundle exec ruby test/suite_filter_test.rb
13
+ MINITEST_SUITE_ONLY="suite1, suite2" bundle exec ruby test/suite_filter_test.rb
14
+ MINITEST_SUITE_ONLY="suite1,suite2,suite3" bundle exec ruby test/suite_filter_test.rb
15
+ MINITEST_SUITE_ONLY="nonsense" bundle exec ruby test/suite_filter_test.rb
16
+ MINITEST_SUITE_EXCEPT="suite1" bundle exec ruby test/suite_filter_test.rb
17
+ MINITEST_SUITE_EXCEPT="suite1,suite3" bundle exec ruby test/suite_filter_test.rb
18
+ MINITEST_SUITE_EXCEPT="suite1,suite2,suite3" bundle exec ruby test/suite_filter_test.rb
19
+ MINITEST_SUITE_EXCEPT="nonsense" bundle exec ruby test/suite_filter_test.rb
20
+
21
+ ORDER="" bundle exec ruby test/suite_fixed_order_test.rb
22
+ ORDER="suite1" bundle exec ruby test/suite_fixed_order_test.rb
23
+ ORDER="suite2,suite3" bundle exec ruby test/suite_fixed_order_test.rb
24
+ ORDER="suite3,suite2,suite1" bundle exec ruby test/suite_fixed_order_test.rb
25
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minitest-suite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Searls
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-31 00:00:00.000000000 Z
11
+ date: 2021-08-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -44,7 +44,9 @@ files:
44
44
  - example/Gemfile
45
45
  - example/Gemfile.lock
46
46
  - example/Rakefile
47
- - example/test/sweet_test.rb
47
+ - example/test/suite_filter_test.rb
48
+ - example/test/suite_fixed_order_test.rb
49
+ - example/test/suite_shuffle_test.rb
48
50
  - lib/minitest/suite.rb
49
51
  - lib/minitest/suite/version.rb
50
52
  - minitest-suite.gemspec