Skip to content

Instantly share code, notes, and snippets.

@latortuga
Last active August 29, 2015 14:27
Show Gist options
  • Save latortuga/267ed13daae0720b597d to your computer and use it in GitHub Desktop.
Save latortuga/267ed13daae0720b597d to your computer and use it in GitHub Desktop.
ARGH-V

Run tests via Minitest how it's supposed to work

# manual way
Minitest.run(args)

# magic way
require 'minitest/autorun'
# or
Minitest.autorun

Minitest autorun

# Minitest 4
def self.autorun
  at_exit {
    exit_code = nil
    at_exit {
      @@after_tests.reverse_each(&:call)
      exit false if exit_code && exit_code != 0
    }
    exit_code = MiniTest::Unit.new.run ARGV
  } unless @@installed_at_exit
  @@installed_at_exit = true
end

# Minitest 5
def self.autorun
  at_exit {
    next if $! and not $!.kind_of? SystemExit
    exit_code = nil
    at_exit {
      @@after_run.reverse_each(&:call)
      exit exit_code || false
    }
    exit_code = Minitest.run ARGV
  } unless @@installed_at_exit
  @@installed_at_exit = true
end

Problem! - double test runs.

$ zeus start
$ zeus test test/models/member_test.rb 
Run options: --seed 51413

# Running tests:

....................

Fabulous tests in 2.431165s, 8.2265 tests/s, 9.4605 assertions/s.

20 tests, 23 assertions, 0 failures, 0 errors, 0 skips
Run options: --seed 61954

# Running tests:

....................

Fabulous tests in 1.473757s, 13.5708 tests/s, 15.6064 assertions/s.

20 tests, 23 assertions, 0 failures, 0 errors, 0 skips

WTF

Zeus terrible integration

def test_helper
  # don't let minitest setup another exit hook
  begin
    require 'minitest/unit'
    if defined?(Minitest::Runnable)
      # Minitest 5
      MiniTest.class_variable_set('@@installed_at_exit', true)
    elsif defined?(MiniTest)
      # Old versions of Minitest
      MiniTest::Unit.class_variable_set("@@installed_at_exit", true)
    end
  end
end

def nerf_test_unit_autorunner
  return unless defined?(Test::Unit::Runner)
  if Test::Unit::Runner.class_variable_get("@@installed_at_exit")
    Test::Unit::Runner.class_variable_set("@@stop_auto_run", true)
  end
end

def execute
  case framework
  when :minitest5
    nerf_test_unit_autorunner
    exit(Minitest.run(test_arguments) ? 0 : 1)
  when :minitest_old
    nerf_test_unit_autorunner
    exit(MiniTest::Unit.runner.run(test_arguments).to_i)
  end
end

Elegant (maybe) fix

Array#replace

irb> ARGV.class
=> Array
irb> ARGV.replace ['abc', 123]
=> ['abc', 123]
require 'minitest/autorun'
# ...
when :minitest5, :minitest_old
  ARGV.replace(test_arguments)
  exit

Lessons

  • Don't mess with the internals of code you don't control
  • Give people sane public APIs so they don't have to mess with your internals
  • Don't change ARGV, unless it's really convenient
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment