Minitest - NoMethodError: undefined method `get' - ruby-on-rails

I was stuck with error when i run very simple test with minitest-rails gem.
I have rails 4.1.5 and minitest 5.4.0
rake test:controllers
1) Error:
DashboardController::index action#test_0001_anonymous:
NoMethodError: undefined method get' for #<#<Class:0x00000008e28170>:0x00000008eeb9b8>
test/controllers/dashboard_controller_test.rb:6:inblock (3 levels) in '
Test:
require "test_helper"
describe DashboardController do
context "index action" do
before do
get :index
end
it { must_respond_with :success }
it "must render index view" do
must_render_template :index
end
end
end
My test_helper:
ENV["RAILS_ENV"] = "test"
require File.expand_path("../../config/environment", __FILE__)
require "rails/test_help"
require "minitest/rails"
require "minitest/rails/capybara"
class MiniTest::Spec
class << self
alias :context :describe
end
end
class RequestTest < MiniTest::Spec
include Rails.application.routes.url_helpers
register_spec_type(/request$/, self)
end
class ActionDispatch::IntegrationTest
# Register "request" tests to be handled by IntegrationTest
register_spec_type(/Request( ?Test)?\z/i, self)
end
class ActiveSupport::TestCase
ActiveRecord::Migration.check_pending!
# Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
#
# Note: You'll currently still have to declare fixtures explicitly in integration tests
# -- they do not yet inherit this setting
fixtures :all
# Add more helper methods to be used by all tests here...
extend MiniTest::Spec::DSL
end

There are many things wrong with what you are doing. As I understand it you want to use Minitest's spec DSL in your Rails tests, correct? It looks like you are doing things to accomplish this that you don't need to do. I don't understand why half that code in your test_helper.rb file is there. I also suspect that you have other code doing things that are not being shown.
Here is what I did to reproduce your setup:
$ echo "Creating a new Rails app"
☣ [rails41:rails41] $ rails new undefined_get
☣ [rails41:rails41] $ cd undefined_get/
$ echo "Generate a Dashboard controller"
$ rails g controller dashboard index
$ echo "Add minitest-rails dependencies"
$ echo 'gem "minitest-rails"' >> Gemfile
$ echo 'gem "minitest-rails-capybara"' >> Gemfile
$ bundle install
$ echo "The test runs fine now:"
$ rake test
Run options: --seed 47210
# Running:
.
Finished in 0.457972s, 2.1835 runs/s, 2.1835 assertions/s.
1 runs, 1 assertions, 0 failures, 0 errors, 0 skips
$ echo "Update to your test code and test_helper code"
$ echo "Use whatever editor you want. Not shown here."
$ echo "Now rerun the tests:"
$ rake test
rake aborted!
NoMethodError: undefined method `context' for #<Class:0x007f860258ae50>
The error I get is different than yours. You aliased the method context to describe in your test_helper.rb file, but unfortunately the object you aliased is not in the inheritance chain for the rails test objects. The rails test objects extend Minitest::Spec::DSL, but they do not inherit from Minitest::Spec. So, I am strongly suspicious that the code you provided is indeed producing the results you have presented. That said, here is the code in my test_helper.rb that will run your test:
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require "minitest/rails"
require "minitest/rails/capybara"
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
# Allow context to be used like describe
class << self
alias :context :describe
end
# Add more helper methods to be used by all tests here...
end
This is the standard test_helper.rb with two changes. First, it has the requires for minitest-rails and minitest-rails-capybara. That is all you need to do in order to enable the Minitest spec DSL in your rails tests. Second, it adds the alias for context to describe on ActiveSupport::TestCase, which is the basis for all the rails tests. If you want to add tests that do not inherit from ActiveSupport::TestCase then you can also alias it on Minitest::Spec, but that will not help you use context within your controller tests.
Still here? Okay. So why did your code give you a different error than mine? Likely the test object used for your controller tests isn't ActionController::TestCase. I say that because your error was undefined method get. The get method is something that ActionController::TestCase defines, and is not on Minitest::Spec. So, you somehow messed up your Minitest configuration. A simple way to make sure that your tests are using the correct test objects is to add an additional assertion to your test. Like this:
require "test_helper"
describe DashboardController do
context "index action" do
before do
# Make sure we are using the correct test class
self.class.ancestors.must_include ActionController::TestCase
# Continue with setup
get :index
end
it { must_respond_with :success }
it "must render index view" do
must_render_template :index
end
end
end
If that first assertion fails then you know you have done something wrong in your configuration.

Related

How to configure Sorbet with rspec?

I have a simple test but the describe keyword is not working in Sorbet tests.
The error I'm receiving on these methods:
Method `describe` does not exist on `T.class_of(<root>)`7003
RSpec.describe(Model) do
describe 'my test' do
before(:each) do # .before error
user = FactoryBot.create(:user)
end
it 'can fill in all fields' do # .it errors
end
end
end
I think I need to tell Sorbet some how that this is called in the context of spec_helper.rbbut I'm not sure how to do that.
I've already installed this gem rspec-sorbet and ran
spec/spec_helper.rb
require 'rspec/sorbet'
To silence the errors, I ran this:
RSpec.describe(Model) do
T.bind(self, T.untyped)
# T.bind(self, RSpec) This does not work either
end

Is there a way to cleanup database tests in Rails 6.0.3.1 System Tests. I thought Rails does the cleanup?

Using
Ruby "2.7.1"
Rails "6.0.3.1"
Mac OS Catalina 10.15.5
Using the default Rails Minitest and FactoryBot for test data.
Issue: I have test data being shared between system test files and hence failing tests. When I run the system test files individually the tests pass but this is inconvenient.
I use the the system test config out of the box as in the application_system_test_case.rb
This is my system test scenario.
I have 3 Customers in customers_system_test.rb file and 1 Customer (so far) in job_description_system_test.rb Customer 1 appears in the customers_system_test.rb failing test screenshots that Rails conveniently provide.
Note: The 3 failing tests all concern record counts such as assert_equal Customer.count, 3
The 3 failing tests
test "visit create customer and navigate back" do
...
assert_equal Customer.count, 3
end
test "cancel destroying a customer" do
assert_equal Customer.count, 3
...
end
test "destroy a customer" do
assert_equal Customer.count, 3
...
end
Interestingly I had the same issue with test data not being cleaned up when running rails test for controller, integration tests etc: The way I get around that is adding the following snippet to the test_helper.rb :
(ActiveRecord::Base.connection.tables - %w{schema_migrations}).each do |table_name|
ActiveRecord::Base.connection.execute "TRUNCATE TABLE #{table_name} CASCADE;"
end Doesn't work for system tests
I feel like I am missing the obvious?
test_helper.rb
require "simplecov"
SimpleCov.start "rails"
ENV["RAILS_ENV"] ||= "test"
require_relative "../config/environment"
require "rails/test_help"
class ActiveSupport::TestCase
include FactoryBot::Syntax::Methods
include Warden::Test::Helpers
# Run tests in parallel with specified workers
# parallelize(workers: :number_of_processors)
parallelize(workers: 1)
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
# fixtures :all
# Add more helper methods to be used by all tests here...
include Devise::Test::IntegrationHelpers
end
(ActiveRecord::Base.connection.tables - %w{schema_migrations}).each do |table_name|
ActiveRecord::Base.connection.execute "TRUNCATE TABLE #{table_name} CASCADE;"
end
Ok I got all tests running and passing including system tests by doing the following (wasn't aware this was necessary in Rails 6)
...
setup do
sign_in user
#customer_1 = FactoryBot.create(:customer_with_job_descriptions)
#job_description_2 = FactoryBot.create(:job_description, customer_id: #customer_1.id)
end
teardown do
#customer_1.destroy!
#job_description_2.destroy!
end
...
Ref: 8 Setup and Teardown
https://guides.rubyonrails.org/v3.2/testing.html#setup-and-teardown
........................................................................................
Finished in 22.971069s, 4.3968 runs/s, 21.4182 assertions/s.
101 runs, 492 assertions, 0 failures, 0 errors, 0 skips

rspec `described_class` is `nil`

Rails 6.0.0.beta3
rspec 3.8.0
I've just installed rspec-rails on my Rails app. I ran rails g rspec:install and it generated spec/spec_helper.rb, spec/rails_helper.rb and .rspec
The only thing I changed was uncommenting the suggested settings in spec_helper
I'm using gruf to run a gRPC server, instead of a normal HTTP server.
I've also installed gruf-rspec intending to use that to test my gruf controllers.
My gruf controller is at app/rpc/controllers/users_controller.rb following the gruf documentation. Also the compiled protobuf file is at app/rpc/users_services_pb.rb
This is the class signature of the controller:
require 'users_services_pb'
require_relative 'permission_helper'
class UsersController < Gruf::Controllers::Base
bind ::Sil::Rev79::Users::Service
...
end
My problem is that in my test the described_class is nil
Here is my test
# spec/rpc/users_contollers_spec.rb
require 'rails_helper'
require 'users_services_pb'
RSpec.describe 'UsersController' do
describe 'list_users' do
it 'succeeds' do
expect(described_class).not_to be_nil
end
end
end
The test fails.
Why is described_class nil and how can I fix this?
Remove the quotation marks. It shouldn't be a string.
Rspec.describe UsersController do
# insert code
end

Why doesn't Minitest run any tests?

I've used Minitest on several projects (both strictly Ruby and Rails) and haven't had much of an issue. I just set up a Rails 4 project with Minitest and can't get the tests to run for some reason. This must be a stupid mistake on my part, but I can't see it.
The "error", "minitest running 0 tests", happens whether I use rake or ruby Itest.
I should also say that I know the test file is being recognized because if I take out the describe block, and just have it should..., I get a NoMethodError - undefined method "it" for CalendarMakerTest:Class.
#test
require 'test_helper'
class CalendarMakerTest < ActionView::TestCase
describe "subject" do
it "does something" do
assert_equal false
end
end
end
#test_helper
require 'minitest/autorun'
require 'minitest/spec'
ENV["RAILS_ENV"] ||= "test"
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
class ActiveSupport::TestCase
ActiveRecord::Migration.check_pending!
end
$ruby -Itest test/helpers/calendar_maker_test.rb
Run options: --seed 33758
# Running tests:
Finished tests in 0.035027s, 0.0000 tests/s, 0.0000 assertions/s.
0 tests, 0 assertions, 0 failures, 0 errors, 0 skips
You can remove the line
class CalendarMakerTest < ActionView::TestCase
Along with the corresponding end statement. You will have better luck.
You are mixing up the ways to use Minitest with the spec and the autotest methodology.
You also don't technically need require minitest/spec when you require minitest/autorun.

How to Test Factories First with Minitest but without the spec framework?

I found a blog post about Testing Factories First (by BigBinary - which happens to be a Minitest/spec version of Thoughtbot's RSpec original).
Could you please show me the equivalent without the spec framework - just with Minitest (Rails)?
The Thoughtbot approach (RSpec)
spec/factories_spec.rb
FactoryGirl.factories.map(&:name).each do |factory_name|
describe "The #{factory_name} factory" do
it 'is valid' do
build(factory_name).should be_valid
end
end
end
Rakefile
if defined?(RSpec)
desc 'Run factory specs.'
RSpec::Core::RakeTask.new(:factory_specs) do |t|
t.pattern = './spec/factories_spec.rb'
end
end
task spec: :factory_specs
The BigBinary approach (Minitest, spec)
spec/factories_spec.rb
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
describe FactoryGirl do
EXCEPTIONS = %w(base_address base_batch bad_shipping_address)
FactoryGirl.factories.each do |factory|
next if EXCEPTIONS.include?(factory.name.to_s)
describe "The #{factory.name} factory" do
it 'is valid' do
instance = build(factory.name)
instance.must_be :valid?
end
end
end
end
lib/tasks/factory.rake
desc 'Run factory specs.'
Rake::TestTask.new(:factory_specs) do |t|
t.pattern = './spec/factories_spec.rb'
end
task test: :factory_specs
What is the Minitest equivalent (without spec)?
The approach I am presenting below is slightly different than the two original solutions - in the sense that my approach creates only one test, within which I cycle through the factories and run an assertion against each. I was not able to create a solution that mimics the original solutions any closer - which is (I believe) a separate test method for each factory. If someone could show such an implementation, that would be cool.
test/aaa_factories_tests/factories_test.rb
require File.expand_path(File.dirname(__FILE__) + '/../test_helper.rb')
class FactoriesTest < Minitest::Unit::TestCase
puts "\n*** Factories Test ***\n\n"
EXCEPTIONS = %w(name_of_a_factory_to_skip another_one_to_skip)
def test_factories
FactoryGirl.factories.each do |factory|
next if EXCEPTIONS.include?(factory.name.to_s)
instance = FactoryGirl.build(factory.name)
assert instance.valid?, "invalid factory: #{factory.name}, error messages: #{instance.errors.messages.inspect}"
instance = factory = nil
end
end
end
Thanks to the way Minitest works out of the box -- add any directories under test/ and minitest-rails will automatically create the associated rake task for it. So let's say you add a test/api/ directory, rake minitest:api will automagically be available. -- I see the task when I run bundle exec rake -T with no other configurations:
rake minitest:aaa_factories_tests # Runs tests under test/aaa_factories_tests
And I am able to run this task successfully:
-bash> bundle exec rake minitest:aaa_factories_tests
*** Factories Test ***
Run options: --seed 19208
# Running tests:
.
Finished tests in 0.312244s, 3.2026 tests/s, 9.6079 assertions/s.
1 tests, 3 assertions, 0 failures, 0 errors, 0 skips
Despite the ugliness of prepending the directory with aaa, I am able to have the factories tested first with:
bundle exec rake minitest:all
The reason for the aaa prepend solution is MiniTest does a Dir glob and on Mac OS X (and other Unix variants) the results are sorted alphabetically (though the results differ across different platforms).
As well, I prepended the default_tasks array with aaa_factories_tests to have the factories tested first in the default Minitest task (i.e. when running bundle exec rake minitest).
lib/tasks/factories_first.rake
MiniTest::Rails::Testing.default_tasks.unshift('aaa_factories_tests') if Rails.env =~ /^(development|test)\z/
Note that the above condition avoids erroneously referencing Minitest in environments where it is unavailable (I have confined minitest-rails to :test and :development groups in Gemfile). Without this if-condition, pushing to Heroku (for example to staging or production) will result in uninitialized constant MiniTest.
Of course I am also able to run the factories test directly:
bundle exec ruby -I test test/aaa_factories_tests/factories_test.rb
Here is a solution for MiniTest without the spec framework:
test/factories_test.rb
require File.expand_path(File.dirname(__FILE__) + '/test_helper')
class FactoriesTest < ActiveSupport::TestCase
EXCEPTIONS = %w(griddler_email)
FactoryBot.factories.map(&:name).each do |factory_name|
next if factory_name.to_s.in?(EXCEPTIONS)
context "The #{factory_name} factory" do
should 'be valid' do
factory = build(factory_name)
assert_equal true, factory.valid?, factory.errors.full_messages
end
end
end
end
lib/tasks/factory.rake
namespace :test do
desc 'Test factories'
Rake::TestTask.new(:factories) do |t|
t.pattern = './test/factories_test.rb'
end
end
task minitest: 'test:factories'
The most important thing is to use taks minitest instead of task test if you want the factories tests to be run before other tests.

Resources