Skip to content

Commit 14c44a6

Browse files
committed
Support Minitest v6
Minitest v6 was released on 2025-12-18. see: https://github.com/minitest/minitest/releases/tag/v6.0.0 These changes make test-queue work with Minitest v6.
1 parent e1674e1 commit 14c44a6

File tree

8 files changed

+417
-2
lines changed

8 files changed

+417
-2
lines changed

.github/workflows/test.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,15 @@ jobs:
2424
- { name: cucumber1_3, bats: test/cucumber.bats }
2525
- { name: cucumber2_4, bats: test/cucumber.bats }
2626
- { name: minitest5, bats: test/minitest5.bats }
27+
- { name: minitest6, bats: test/minitest6.bats }
2728
- { name: rspec3, bats: test/rspec3.bats }
2829
- { name: rspec4, bats: test/rspec4.bats }
2930
- { name: testunit, bats: test/testunit.bats }
3031
- { name: turnip, bats: test/turnip.bats }
32+
exclude:
33+
# Minitest 6 requires Ruby 3.2+
34+
- ruby: '2.7'
35+
entry: { name: minitest6, bats: test/minitest6.bats }
3136

3237
steps:
3338
- name: checkout

Appraisals

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ appraise 'minitest5' do
1717
gem 'minitest', '5.10.0'
1818
end
1919

20+
appraise 'minitest6' do
21+
gem 'rake'
22+
gem 'minitest', '~> 6.0'
23+
end
24+
2025
appraise 'rspec3' do
2126
gem 'rspec', '~> 3.12'
2227
end

gemfiles/minitest6.gemfile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# frozen_string_literal: true
2+
3+
# This file was generated by Appraisal
4+
5+
source 'https://rubygems.org'
6+
7+
gem 'minitest', '~> 6.0'
8+
gem 'rake'
9+
10+
gemspec path: '../'

lib/test_queue/runner/minitest.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@
22

33
require 'minitest'
44

5-
raise 'requires Minitest version 5' unless Minitest::VERSION.to_i == 5
5+
minitest_version = Minitest::VERSION.to_i
6+
raise 'requires Minitest version 5 or 6' unless minitest_version == 5 || minitest_version == 6
67

7-
require_relative '../runner/minitest5'
8+
if minitest_version == 5
9+
require_relative '../runner/minitest5'
10+
else
11+
require_relative '../runner/minitest6'
12+
end
813

914
module TestQueue
1015
class Runner

lib/test_queue/runner/minitest6.rb

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# frozen_string_literal: true
2+
3+
require_relative '../runner'
4+
5+
module Minitest
6+
def self.run_all_suites(reporter, options)
7+
suites = Runnable.runnables
8+
suites.map { |suite| suite.run_suite reporter, options }
9+
end
10+
11+
class Runnable
12+
def failure_count
13+
failures.length
14+
end
15+
end
16+
17+
class Test
18+
def self.runnables=(runnables)
19+
@@runnables = runnables
20+
end
21+
22+
# Synchronize all tests, even serial ones.
23+
#
24+
# Minitest runs serial tests before parallel ones to ensure the
25+
# unsynchronized serial tests don't overlap the parallel tests. But since
26+
# the test-queue master hands out tests without actually loading their
27+
# code, there's no way to know which are parallel and which are serial.
28+
# Synchronizing serial tests does add some overhead, but hopefully this is
29+
# outweighed by the speed benefits of using test-queue.
30+
def _synchronize
31+
Test.io_lock.synchronize { yield }
32+
end
33+
end
34+
35+
class ProgressReporter
36+
# Override original method to make test-queue specific output
37+
def record(result)
38+
io.print ' '
39+
io.print result.klass
40+
io.print ': '
41+
io.print result.result_code
42+
io.puts(' <%.3f>' % result.time)
43+
end
44+
end
45+
46+
begin
47+
require 'minitest/minitest_reporter_plugin'
48+
49+
class << self
50+
private
51+
52+
def total_count(_options)
53+
0
54+
end
55+
end
56+
rescue LoadError
57+
# noop
58+
end
59+
end
60+
61+
module TestQueue
62+
class Runner
63+
class Minitest < Runner
64+
def initialize
65+
@options = ::Minitest.process_args ARGV
66+
67+
if ::Minitest.respond_to?(:seed)
68+
::Minitest.seed = @options[:seed]
69+
srand ::Minitest.seed
70+
end
71+
72+
if ::Minitest::Test.runnables.any? { |r| r.runnable_methods.any? }
73+
raise 'Do not `require` test files. Pass them via ARGV instead and they will be required as needed.'
74+
end
75+
76+
super(TestFramework::Minitest.new)
77+
end
78+
79+
def start_master
80+
puts "Run options: #{@options[:args]}\n\n"
81+
82+
super
83+
end
84+
85+
def run_worker(iterator)
86+
::Minitest::Test.runnables = iterator
87+
::Minitest.run ? 0 : 1
88+
end
89+
end
90+
end
91+
92+
class TestFramework
93+
class Minitest < TestFramework
94+
def all_suite_files
95+
ARGV
96+
end
97+
98+
def suites_from_file(path)
99+
::Minitest::Test.reset
100+
require File.absolute_path(path)
101+
::Minitest::Test.runnables
102+
.reject { |s| s.runnable_methods.empty? }
103+
.map { |s| [s.name, s] }
104+
end
105+
end
106+
end
107+
end

test/examples/example_minispec6.rb

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# frozen_string_literal: true
2+
3+
require 'minitest/spec'
4+
5+
class Meme
6+
def i_can_has_cheezburger?
7+
'OHAI!'
8+
end
9+
10+
def will_it_blend?
11+
'YES!'
12+
end
13+
end
14+
15+
describe Meme do
16+
before do
17+
@meme = Meme.new
18+
end
19+
20+
describe 'when asked about cheeseburgers' do
21+
it 'must respond positively' do
22+
sleep 0.1
23+
_(@meme.i_can_has_cheezburger?).must_equal 'OHAI!'
24+
end
25+
end
26+
27+
describe 'when asked about blending possibilities' do
28+
it "won't say no" do
29+
sleep 0.1
30+
_(@meme.will_it_blend?).wont_match(/^no/i)
31+
end
32+
33+
if ENV['FAIL']
34+
it 'fails' do
35+
_(@meme.will_it_blend?).must_equal 'NO!'
36+
end
37+
end
38+
end
39+
end

test/examples/example_minitest6.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# frozen_string_literal: true
2+
3+
require 'minitest/autorun'
4+
5+
class MinitestEqual < Minitest::Test
6+
def test_equal
7+
assert_equal 1, 1
8+
end
9+
end
10+
11+
30.times do |i|
12+
Object.const_set("MinitestSleep#{i}", Class.new(Minitest::Test) do
13+
define_method(:test_sleep) do
14+
start = Time.now
15+
sleep(0.25)
16+
assert_in_delta Time.now - start, 0.25, 0.02
17+
end
18+
end)
19+
end
20+
21+
if ENV['FAIL']
22+
class MinitestFailure < Minitest::Test
23+
def test_fail
24+
assert_equal 0, 1
25+
end
26+
end
27+
end
28+
29+
if ENV['KILL']
30+
class MinitestKilledFailure < Minitest::Test
31+
def test_kill
32+
Process.kill(9, $$)
33+
end
34+
end
35+
end

0 commit comments

Comments
 (0)