freerange / mocha

A mocking and stubbing library for Ruby

Home Page:https://mocha.jamesmead.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Mocha is incompatible with minitest v5.19 and later

kyrofa opened this issue · comments

Minitest has removed the ancient MiniTest compatibility layer that Mocha has been relying on unless the user defines the MT_COMPAT environment variable. See the commit for more details.

Seems that Mocha should move to using Minitest instead?

@kyrofa:

Thanks for the heads up, although I'm a bit confused about what's broken. I just manually ran the weekly build which tries to pick up on incompatibilities like this, but nothing failed even though the job using the latest Minitest gem seems to have used v5.19.0 which is the version you mention.

If you understand more about exactly what the problem is, it would be great if you can save me some time and tell me what's actually broken and ideally what I need to change!

And do you know if there was a Minitest deprecation warning for this? If so, I missed it!

here's a backtrace if that's helpful:

/Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/mocha-2.0.4/lib/mocha/integration/mini_test/adapter.rb:26:in `included': uninitialized constant MiniTest (NameError)

          Mocha::ExpectationErrorFactory.exception_class = ::MiniTest::Assertion
                                                                     ^^^^^^^^^^^
Did you mean?  Minitest
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/mocha-2.0.4/lib/mocha/integration/mini_test.rb:21:in `include'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/mocha-2.0.4/lib/mocha/integration/mini_test.rb:21:in `activate'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/mocha-2.0.4/lib/mocha/minitest.rb:4:in `<main>'
	from <internal:/Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from <internal:/Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.9/lib/zeitwerk/kernel.rb:38:in `require'
	from /Users/mikemanewitz/work/coupons/test/test_helper.rb:10:in `<main>'
	from <internal:/Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from <internal:/Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.9/lib/zeitwerk/kernel.rb:38:in `require'
	from /Users/mikemanewitz/work/coupons/test/controllers/bulk_uploads_controller_test.rb:3:in `<main>'
	from <internal:/Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from <internal:/Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.9/lib/zeitwerk/kernel.rb:38:in `require'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/railties-7.0.6/lib/rails/test_unit/runner.rb:47:in `block in load_tests'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/railties-7.0.6/lib/rails/test_unit/runner.rb:47:in `each'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/railties-7.0.6/lib/rails/test_unit/runner.rb:47:in `load_tests'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/railties-7.0.6/lib/rails/test_unit/runner.rb:40:in `run'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/railties-7.0.6/lib/rails/commands/test/test_command.rb:33:in `perform'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/thor-1.2.2/lib/thor/command.rb:27:in `run'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/thor-1.2.2/lib/thor/invocation.rb:127:in `invoke_command'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/honeybadger-5.2.1/lib/honeybadger/plugins/thor.rb:17:in `invoke_command_with_honeybadger'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/thor-1.2.2/lib/thor.rb:392:in `dispatch'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/railties-7.0.6/lib/rails/command/base.rb:87:in `perform'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/railties-7.0.6/lib/rails/command.rb:48:in `invoke'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/railties-7.0.6/lib/rails/commands.rb:18:in `<main>'
	from <internal:/Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from <internal:/Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/bootsnap-1.16.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require'
	from /Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.9/lib/zeitwerk/kernel.rb:38:in `require'
	from /Users/mikemanewitz/work/coupons/bin/rails:5:in `<main>'
	from <internal:/Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
	from <internal:/Users/mikemanewitz/.asdf/installs/ruby/3.2.2/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
	from -e:1:in `<main>'

And do you know if there was a Minitest deprecation warning for this? If so, I missed it!

You and I both 😛 . Not that I know of, no. I logged an issue asking for confirmation that minitest actually uses semver, because I've been operating under the assumption that it does. Hopefully this was just an oversight, but it's a good reminder that we're using pretty old API, here.

I just manually ran the weekly build which tries to pick up on incompatibilities like this, but nothing failed [...].

I'll see if I can work up a minimal reproducer for you.

When I edited the gem locally to use the Minitest casing it fixed my test suite. Might roll back to the last minitest for now.

Yeah I just pinned minitest to < 5.19 for now.

@floehopper run this:

require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"

  gem "minitest", "~> 5.19"
  gem "mocha", "~> 2.0"
end

require "minitest/autorun"
require 'mocha/minitest'

I see this:

$ ruby reproducer.rb 
Fetching gem metadata from https://rubygems.org/..
Resolving dependencies...
Using bundler 2.4.12
Using minitest 5.19.0
Using ruby2_keywords 0.0.5
Fetching mocha 2.0.4
Installing mocha 2.0.4
Traceback (most recent call last):
	5: from reproducer.rb:11:in `<main>'
	4: from reproducer.rb:11:in `require'
	3: from /home/kyrofa/.rvm/gems/ruby-2.7.5/gems/mocha-2.0.4/lib/mocha/minitest.rb:4:in `<top (required)>'
	2: from /home/kyrofa/.rvm/gems/ruby-2.7.5/gems/mocha-2.0.4/lib/mocha/integration/mini_test.rb:21:in `activate'
	1: from /home/kyrofa/.rvm/gems/ruby-2.7.5/gems/mocha-2.0.4/lib/mocha/integration/mini_test.rb:21:in `include'
/home/kyrofa/.rvm/gems/ruby-2.7.5/gems/mocha-2.0.4/lib/mocha/integration/mini_test/adapter.rb:26:in `included': uninitialized constant MiniTest (NameError)
Did you mean?  Minitest

Works fine with minitest < 5.19.

@manewitz:

Thanks for the backtrace - it certainly gives me a bit more to go on!

When I edited the gem locally to use the Minitest casing it fixed my test suite. Might roll back to the last minitest for now.

Did you rename all occurrences of MiniTest -> Minitest throughout the Mocha codebase to fix it? That seems a bit challenging if we need to do that, because it will mean Mocha is no longer compatible with older versions of Minitest!

@kyrofa Many thanks for the code to reproduce the problem 👍

That seems a bit challenging if we need to do that, because it will mean Mocha is no longer compatible with older versions of Minitest!

I definitely appreciate that mindset, but it's worth a look at minitest. I'd be willing to bet the Minitest module has been "the way" for a very long time. The versions of minitest that only have MiniTest are probably extremely old.

@manewitz:

Thanks for the backtrace - it certainly gives me a bit more to go on!

When I edited the gem locally to use the Minitest casing it fixed my test suite. Might roll back to the last minitest for now.

Did you rename all occurrences of MiniTest -> Minitest throughout the Mocha codebase to fix it? That seems a bit challenging if we need to do that, because it will mean Mocha is no longer compatible with older versions of Minitest!

I just updated the one call in lib/mocha/integration/mini_test/adapter.rb:26 and it worked for me

@manewitz

I just updated the one call in lib/mocha/integration/mini_test/adapter.rb:26 and it worked for me

Yes, that seems to do the trick for me too (I've opened #615 to demo that), although I think there might be a bunch of other stuff to check and definitely some code to clean up. If anyone has a project with a lot of tests that using Mocha, it would be great if you could point your Gemfile at the fix-minitest-compatibility branch and see if you run into any other problems, i.e.

# Gemfile

gem "mocha", github: "freerange/mocha", branch: "fix-minitest-compatibility"
  1. Yes, the name change is over a decade old.
  2. All that has changed is not requiring the cruft file.
  3. You can require "minitest/unit" to avoid changing all instances of MiniTest to Minitest (but... c'mon... a decade).
  4. Literally nothing else has changed.

because it will mean Mocha is no longer compatible with older versions of Minitest

no

Fix released in v2.1.0. Thanks for your help, @kyrofa, @manewitz & @zenspider.

Thanks @floehopper, really appreciate it!