performance testing with devise authentication - ruby-on-rails

How can I run performance tests with devise. Using the Devise docs I have this in my test_helper.rb
class ActionController::TestCase
include Devise::TestHelpers
end
From Functional testing with Rails and Devise. What to put in my fixtures?, I have this in my performance test:
require 'test_helper'
require 'rails/performance_test_help'
class EditorTest < ActionDispatch::PerformanceTest
def test_create
#user = users(:one)
sign_in #user
get 'documents/new/1'
end
end
I get the following error
NoMethodError: undefined method `sign_in' for #<EditorTest:0xb6bc0654 ...>
/test/performance/editor_test.rb:9:in `test_create'
How do I properly include the Devise TestHelpers in a performance test?
Thank you!
[edit]
This works as a functional test.
[edit]
After including the devise helper in ActionDispatch::PerformanceTest and running the test with ruby -d, here is the bottom of the debug output:
/usr/lib/ruby/gems/1.8/gems/devise-1.1.rc2/lib/devise/test_helpers.rb:
53: warning: instance variable #request not initialized
Exception `NoMethodError' at /usr/lib/ruby/gems/1.8/gems/
activesupport-3.0.3/lib/active_support/whiny_nil.rb:48 - undefined
method `env' for nil:NilClass
EEditorTest#test_create (0 ms warmup)
/usr/lib/ruby/gems/1.8/gems/devise-1.1.rc2/lib/devise/test_helpers.rb:
53: warning: instance variable #request not initialized
Exception `NoMethodError' at /usr/lib/ruby/gems/1.8/gems/
activesupport-3.0.3/lib/active_support/whiny_nil.rb:48 - undefined
method `env' for nil:NilClass
E process_time: 0 ms
Exception `Errno::EEXIST' at /usr/lib/ruby/1.8/fileutils.rb:243 -
File
exists - tmp/performance
Exception Errno::EEXIST' at /usr/lib/ruby/1.8/fileutils.rb:243 -
File
exists - tmp/performance
ExceptionErrno::EEXIST' at /usr/lib/ruby/1.8/fileutils.rb:243 -
File
exists - tmp/performance
The short version of the above error:
NoMethodError: undefined method `env' for nil:NilClass

(Misread question original reply to the wrong question is below.)
Try adding
class ActionDispatch::PerformanceTest
include Devise::TestHelpers
end
to the bottom of your helper file.
(Original reply)
Make sure
class ActionController::TestCase
include Devise::TestHelpers
end
is all the way at the bottom of your helper file. It should NOT be inside the ActiveSupport::TestCase class.

It seems performance tests don't set a request variable, which Devise test helpers try to access. In other words, Devise test helpers won't help you here.
As suggested to you here http://groups.google.com/group/plataformatec-devise/browse_thread/thread/b50bfd8ecb24822c try filling in the sign in form like in integration tests.
This explains how integration tests work, with an example how to sign in: http://guides.rubyonrails.org/testing.html#integration-testing

Related

Rails 6 Integration test exception is too long

I have just set up a brand new rails 6.1 application on Ruby 3.0.
Everything is working as expected, except for the IntegrationTest.
Whenever there's a error in the test, the stack trace is gigantic and unreadable. I'm not sure if it's a wrong config or a bug. It's so long it doesn't fit VSCode terminal. I had to pop up a system terminal to be able to go to the first line of the stack trace and understand what's going on
Here's an snippet of the stack trace:
rails test test/controllers/api/v1/sessions_controller_test.rb:23
E
Error:
API::V1::SessionsControllerTest#test_it_generates_token_on_successfull_auth:
NameError: undefined local variable or method `password' for #<API::V1::SessionsControllerTest:0x000000012d5d6ca8 #_routes=nil, #NAME="test_it_generates_token_on_successfull_auth", #failures=[#<Minitest::UnexpectedError: Unexpected exception>], #assertions=0, #integration_session=#<#<Class:0x0000000107222768>:0x00000001072221a0 #_routes=nil, #app=#<OcaServer::Application:0x000000011db277d0 #_all_autoload_paths=["/Users/joao/code/one_cent_auction/oca_server/app/channels", "/Users/joao/code/one_cent_auction/oca_server/app/controllers", "/Users/joao/code/one_cent_auction/oca_server/app/controllers/concerns", "/Users/joao/code/one_cent_auction/oca_server/app/helpers", "/Users/joao/code/one_cent_auction/oca_server/app/jobs", "/Users/joao/code/one_cent_auction/oca_server/app/mailers", "/Users/joao/code/one_cent_auction/oca_server/app/models", "/Users/joao/code/one_cent_auction/oca_server/app/models/concerns", "/Users/joao/code/one_cent_auction/oca_server/app/services"], #_all_load_paths=["/Users/joao/code/one_cent_auction/oca_server/lib", "/Users/joao/code/one_cent_auction/oca_server/vendor", "/Users/joao/code/one_cent_auction/oca_server/app/channels", "/Users/joao/code/one_cent_auction/oca_server/app/controllers", "/Users/joao/code/one_cent_auction/oca_server/app/controllers/concerns", "/Users/joao/code/one_cent_auction/oca_server/app/helpers", "/Users/joao/code/one_cent_auction/oca_server/app/jobs", "/Users/joao/code/one_cent_auction/oca_server/app/mailers", "/Users/joao/code/one_cent_auction/oca_server/app/models", "/Users/joao/code/one_cent_auction/oca_server/app/models/concerns", "/Users/joao/code/one_cent_auction/oca_server/app/services"], #app=#<ActionDispatch::HostAuthorization:0x000000010f88e5b8 #app=#<Rack::Sendfile:0x000000010f88e770 #app=#<ActionDispatch::Static:0x000000012d407350 #app=#<ActionDispatch::Executor:0x000000012d407490 #app=#<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x000000011dc782d8 #name="ActiveSupport::Cache::Strategy::LocalCache", #local_cache_key=:active_support_cache_null_store_local_cache_4540, #app=#<Rack::Runtime:0x000000012d4076c0 #app=#<Rack::MethodOverride:0x000000012d407800 #app=#<ActionDispatch::RequestId:0x000000012d407a30 #app=#<ActionDispatch::RemoteIp:0x000000012d407b98 #app=#<Rails::Rack::Logger:0x000000012d407cd8 #app=#<ActionDispatch::ShowExceptions:0x000000012d407dc8 #app=#<ActionDispatch::DebugExceptions:0x000000012d407ee0 #app=#<ActionDispatch::
It goes on for thousands of lines.
Here's my test_helper
ENV['RAILS_ENV'] ||= 'test'
require_relative "../config/environment"
require "rails/test_help"
require 'webmock/minitest'
class ActiveSupport::TestCase
include FactoryBot::Syntax::Methods
# Run tests in parallel with specified workers
parallelize(workers: :number_of_processors)
# 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...
end
On another project that I am working on there was never an stacktrace that was that big.
-- Edit
Just to clarify what's triggering the error:
require 'test_helper'
class API::V1::SessionsControllerTest < ActionDispatch::IntegrationTest
setup do
#password = Faker::Internet.password
#user = create(:user)
#user.update! password: password, password_confirmation: password
end
#...
end
The error is happening because I called a variable that hasnt been declared. password instead of #password
The problem is that I was expecting the stack trace to be as simple as:
API::V1::SessionsControllerTest#test_it_generates_token_on_successfull_auth:
NameError: undefined local variable or method `password' for #<API::V1::SessionsControllerTest:0x000000012d5d6ca8>
And not show the entire content of the SessionsControllerTest class.
Is that a normal Rails 6.1 behavior on Ruby 3? I don't recall it happening on Ruby 2.
Here's what I was expecting, reproducing the same error on a Ruby 2, Rails 6.1 application:
rails test test/controllers/jobs_controller_test.rb:15
E
Error:
JobsControllerTest#test_should_get_index:
NameError: undefined local variable or method `it_will_fail' for #<JobsControllerTest:0x0000000115b7c620>
test/controllers/jobs_controller_test.rb:6:in `block in <class:JobsControllerTest>'
test/test_helper.rb:24:in `run'

Rails /lib use in fixtures

I have some common code that I have abstracted to a module in my /lib directory:
module ExampleModule
def self.do_something
# return a value
end
end
I need to use this method in my test fixtures, however I am getting the following error when I run tests:
Error:
SomeTest#test_that_something:
NoMethodError: undefined method `do_something' for ExampleModule:Module
test/fixtures/model_name.yml:4:in `get_binding'
How can I access this method in the test fixtures? I can fix the error by requiring the module in other parts of the app that are loaded during test, but how would I require this module if it was needed specifically in the fixture file here? Would I need to require it in any test using the fixture?

Rails 5 Integration test fails with NoMethodError: undefined method `[]=' for nil:NilClass when using Devise helper sign_in

I'm writing an integration test for Rails v5.1 using built-in Minitest.
Here's the integration test class:
require 'test_helper'
class PuppiesEndpointsTest < ActionDispatch::IntegrationTest
include Devise::Test::IntegrationHelpers
test "DELETE puppy" do
marty = people(:marty)
sign_in(marty)
# delete puppies_delete_path(marty.puppies.first.id)
# delete `/api/v1/puppies/destroy/${marty.puppies.first.id}.json`
# delete puppies_path(marty.puppies.first.id)
delete '/api/v1/puppies/destroy/6666.json'
assert_response :success
end
end
All of the routes above, including the ones that are commented out, result in the same cryptic error:
Error:
PuppiesEndpointsTest#test_DELETE_puppy:
NoMethodError: undefined method `[]=' for nil:NilClass
test/integration/puppies_endpoints_test.rb:17:in `block in <class:PuppiesEndpointsTest>'
bin/rails test test/integration/puppies_endpoints_test.rb:7
It doesn't give a stack trace or any other information to diagnose what the hell it's talking about. I used byebug to debug the marty variable right before that delete line that's throwing the error. It shows the expected puppies array of associated (fixture) records.
I've also placed a byebug at the very top of the controller action and this error fails the test before it reaches that byebug, so I think that pretty much rules out anything in the action code.
Here's the relevant chunk of what I see when I run rake routes:
PATCH /api/v1/puppies/edit/:id(.:format) puppies#update
DELETE /api/v1/puppies/destroy/:id(.:format) puppies#destroy
puppies_create POST /api/v1/puppies/create(.:format) puppies#create
Here's what is actually in the my routes file:
scope '/api' do
scope '/v1' do
devise_for :people
patch 'puppies/edit/:id' => 'puppies#update'
delete 'puppies/destroy/:id' => 'puppies#destroy'#, as: 'puppies_delete'
post 'puppies/create' => 'puppies#create'
...
I'm completely stumped as to what/why I'm getting this error. The actual code is working completely as expected.
My hunch is that maybe there's a missing config variable that's not getting set for the test environment (I use dotenv gem), but I have no idea how to track that down if the error won't give me any context whatsoever.
UPDATE
I have isolated this problem to using the Devise helper sign_in method. When I remove this method call, the problem goes away.
Here's the problematic test class:
require 'test_helper'
class PuppiesEndpointsTest < ActionDispatch::IntegrationTest
include Devise::Test::IntegrationHelpers
test "do stuff" do
...
app/controllers/api_controller.rb:
class ApiController < ActionController::API
end
Maybe sign_in does not work for testing controllers that do not inherit from ActionController::Base
I changed the controller to inherit from ActionController::Base and nothing changed. I still can't use sign_in without getting that error, but it works find if I "manually" post a request to the sign_in endpoint.
UPDATE 2
I found this Devise issue which sounds related to my problem: https://github.com/plataformatec/devise/issues/2065
Looks like I found the issue. Apparently, in rails-api mode, the ActionDispatch::Cookies and ActionDispatch::Session::CookieStore middlewares are inserted in the end of the middleware stack, which doesn't occur in normal Rails mode.
Due to this, those middlewares are included after Warden::Manager which messes up something in request specs.
Try to set in test.rb
Rails.application.config.middleware.insert_before Warden::Manager, ActionDispatch::Cookies
Rails.application.config.middleware.insert_before Warden::Manager, ActionDispatch::Session::CookieStore

how do I alias Minitest spec methods

I'm using Minitest spec in a rails project and I want to use must as an alias for must_be and wont as an alias for wont_be
in April 2015 Chris Kottom gave an example of this by doing this:
module Minitest::Expectations
alias_method :must, :must_be
end
But when I try the same it doesn't work. I put that code before my test class and this test:
it 'uses the alias' do
user = User.take
_(user).must(:valid?)
end
gives this error:
Minitest::UnexpectedError: NoMethodError: undefined method `valid?' for #<Minitest::Expectation:0x0055b830595608>
(when I change must to must_be the test passes)
What am I doing wrong?

Devise 3.2 + Rspec 3

I'm trying to build some tests with Rspec and I'm getting the following error:
Failure/Error: get :index
NoMethodError:
undefined method `authenticate!' for nil:NilClass
Then I made some searchs and I realized that I had to include this line in the spec_helper.rb:
RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
end
It seems that this code worked for most people but not for me. Now i'm getting the following error:
/home/bruna/Dropbox/Rails/academico/spec/spec_helper.rb:18:in `block in <top (required)>': uninitialized constant Devise (NameError)
I think this might be some error in this version of rspec and/or devise. Has anyone seen this error? Please, help me :'(
RSpec 3 configuration is different from earlier versions, with the addition of a spec/rails_helper.rb file that must be included for each spec file. Add the Devise TestHelpers to the spec/rails_helper.rb file.
If you need more information about RSpec 3 configuration, I've written an RSpec Tutorial. There's also information about testing Devise with RSpec, including advice about session helpers for feature testing, in my Rails Devise Tutorial.

Resources