Even if specify the use of TestUnit, it will be overwritten by Minitest and cannot be used.
Closed this issue · 6 comments
What Ruby, Rails and RSpec versions are you using?
ruby 3.2.2 (2023-03-30 revision e51014f9c0) [arm64-darwin22]
Rails 7.1.2
RSpec 3.12
- rspec-core 3.12.2
- rspec-expectations 3.12.3
- rspec-mocks 3.12.6
- rspec-rails 6.1.0
- rspec-support 3.12.1
Observed behaviour
Even if I set spec_helper.rb so that TestUnit can also be used, TestUnit's assert does not work.
require "rails_helper"
RSpec.describe type: :model do
it "works" do
pp self.class.ancestors.collect(&:name).grep(/unit|mini/i)
assert { 1 + 2 == 3 }
end
end
# >> ["RSpec::Rails::MinitestAssertionAdapter",
# >> "RSpec::Rails::MinitestLifecycleAdapter",
# >> "RSpec::Core::TestUnitAssertionsAdapter",
# >> "Test::Unit::Assertions"]
# >> F
# >>
# >> Failures:
# >>
# >> 1) {:type=>:model} works
# >> Failure/Error: Unable to find - to read failed line
# >>
# >> ArgumentError:
# >> wrong number of arguments (given 0, expected 1..2)
# >> # -:7:in `block (2 levels) in <main>'
# >>
# >> Finished in 0.01616 seconds (files took 0.91698 seconds to load)
# >> 1 example, 1 failure
# >>
# >> Failed examples:
# >>
# >> rspec -:5 # {:type=>:model} worksExpected behaviour
The assert method of PowerAssert, which is originally installed with TestUnit, is enabled, so assert can be executed with a block.
And the test passes without any problems.
Actual behavior
An error message will be displayed stating that the number of arguments does not match.
# >> ArgumentError:
# >> wrong number of arguments (given 0, expected 1..2)
Cause
The cause is that TestUnit is overwritten with Minitest.
If check ancestors, will see that MinitestAssertionAdapter is included, which is closer than TestUnitAssertionsAdapter.
Specifically, MinitestAssertionAdapter is included in the following two places regardless of the user's intention.
I think this setting allows the user to decide whether to use TestUnit or Minitest.
If I want to use Minitest, configure it explicitly there.
Would it be possible to consider discontinuing the mandatory use of Minitest in RailsExampleGroup and FixtureSupport?
I kindly request your consideration.
Steps to reproduce
- rails new my_rspec_rails_app
- cd my_rspec_rails_app
- bundle add rspec-rails test-unit --group "development, test"
- rails generate rspec:install
- Add
config.expect_with :test_unitto spec/spec_helper.rb
- Create the spec/models/hello_spec.rb below.
https://github.com/akicho8/my_rspec_rails_app/blob/main/spec/models/hello_spec.rb
- Run
rails spec
The entire code is below. Fully reproducible.
https://github.com/akicho8/my_rspec_rails_app
It is also possible to reproduce with just this one file.
require "bundler/inline"
gemfile do
source "https://rubygems.org"
gem "rspec"
gem "rails"
gem "rspec-rails"
gem "test-unit"
end
require "rspec/autorun"
require "test/unit"
require "rails"
require "action_view"
require "action_controller"
require "rspec/rails"
RSpec.configure do |config|
config.expect_with :test_unit
end
RSpec.describe do
include RSpec::Rails::RailsExampleGroup
it "works" do
pp self.class.ancestors.collect(&:name).grep(/unit|mini/i)
assert { 1 + 2 == 3 }
end
end
# >> ["RSpec::Rails::MinitestAssertionAdapter",
# >> "RSpec::Rails::MinitestLifecycleAdapter",
# >> "RSpec::Core::TestUnitAssertionsAdapter",
# >> "Test::Unit::Assertions"]
# >> F
# >>
# >> Failures:
# >>
# >> 1) works
# >> Failure/Error: Unable to find - to read failed line
# >>
# >> ArgumentError:
# >> wrong number of arguments (given 0, expected 1..2)
# >> # -:29:in `block (2 levels) in <main>'
# >>
# >> Finished in 0.005 seconds (files took 0.48997 seconds to load)
# >> 1 example, 1 failure
# >>
# >> Failed examples:
# >>
# >> rspec -:27 # works
Possible related issues
Secondary question:
Would it be possible to consider discontinuing the mandatory use of Minitest in RailsExampleGroup and FixtureSupport?
Not easily at least. Our matchers use Rails-provided assertions internally, e.g.
@pirj Thanks for your comment
RSpec was designed to be able to switch between TesUnit and Minitest. So we naturally assumed that rspec-rails would be able to do the same.
However, from what you say, is rspec-rails designed with the basic assumption that minitest exists to support the expect notation?
If so, it would be a shame if you could make it clear that TestUnit should not be mixed with rspec-rails, but I'll give up and use minitest.
Rails has a dependency on minitest and uses minitest for its test helpers which we bring into RSpec in rspec-rails to enable behaviour similar to those test helpers, so its not possible for rspec-rails to disable minitest entirely, but you should able to preprend the assertion module yourself if you want to use test unit assertions, as this looks to me like an ordering issue, you've enable the config but then rspec-rails comes on top of that...
@JonRowe Thanks for your comment
Since TestUnit and Minitest have the same interface, is it safe to switch between the two?
Also, there may be an ordering issue: Minitest is included more recently than TestUnit in the ancestors results.
Looking in ActiveSupport, there are so many places where it directly says Minitest:: that I have a feeling that replacing only the Minitest assertion with the TestUnit assertion may not work.
For now, I would like to proceed by combining the current spec-rails with the minutest-power_assert gem.
👍 I'm going to close this as not planned but if someone does find a way to allow this to be better prioritised feel free to open a PR