We are trying to test that our controller is calling a class a given number of times based on a param we have, but our test is failing in rspec, saying that the initialize method on our class is returning a nil.
We have this controller:
class ProcessFaxesController < ApplicationController
def create
email = params["From"]
attachment_count = params["attachment-count"].to_i
head :ok
if attachment_count > 0
attachment_count.times do |document_index|
FaxedDocumentProcessor.new(params, document_index+1).perform
end
else
DocumentProcessingMailer.delay.failure_notification(email, "No attachment found.")
end
end
end
The external class:
class FaxedDocumentProcessor
def initialize(params, document_index)
@params = params
@attachment = @params["attachment-#{document_index}"]
@email = @params['From']
end
def perform
# some stuff here
end
end
With this spec:
require 'rails_helper'
RSpec.describe ProcessFaxesController, type: :controller do
context "#create" do
context 'with attachments' do
before { allow_any_instance_of(FaxedDocumentProcessor).to receive(:perform).and_return(true) }
it 'calls the FaxedDocumentProcessor attachment-count times' do
expect(FaxedDocumentProcessor).to receive(:new).twice
post :create, 'email' => 'test@example.com', 'attachment-count' => 2)
end
end
end
end
This is the error we are getting from our test:
Failures:
1) ProcessFaxesController#create with attachments calls the FaxedDocumentProcessor attachment-count times
Failure/Error: FaxedDocumentProcessor.new(params, document_index+1).perform
NoMethodError:
undefined method `perform' for nil:NilClass
# ./app/controllers/process_faxes_controller.rb:20:in `block in create'
# ./app/controllers/process_faxes_controller.rb:19:in `times'
# ./app/controllers/process_faxes_controller.rb:19:in `create'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/actionpack-4.2.6/lib/action_controller/metal/implicit_render.rb:4:in `send_action'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/actionpack-4.2.6/lib/abstract_controller/base.rb:198:in `process_action'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/actionpack-4.2.6/lib/action_controller/metal/rendering.rb:10:in `process_action'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/actionpack-4.2.6/lib/abstract_controller/callbacks.rb:20:in `block in process_action'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/activesupport-4.2.6/lib/active_support/callbacks.rb:117:in `call'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/activesupport-4.2.6/lib/active_support/callbacks.rb:555:in `block (2 levels) in compile'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/activesupport-4.2.6/lib/active_support/callbacks.rb:505:in `call'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/activesupport-4.2.6/lib/active_support/callbacks.rb:92:in `__run_callbacks__'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/activesupport-4.2.6/lib/active_support/callbacks.rb:778:in `_run_process_action_callbacks'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/activesupport-4.2.6/lib/active_support/callbacks.rb:81:in `run_callbacks'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/actionpack-4.2.6/lib/abstract_controller/callbacks.rb:19:in `process_action'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/actionpack-4.2.6/lib/action_controller/metal/rescue.rb:29:in `process_action'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/actionpack-4.2.6/lib/action_controller/metal/instrumentation.rb:32:in `block in process_action'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/activesupport-4.2.6/lib/active_support/notifications.rb:164:in `block in instrument'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/activesupport-4.2.6/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/activesupport-4.2.6/lib/active_support/notifications.rb:164:in `instrument'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/actionpack-4.2.6/lib/action_controller/metal/instrumentation.rb:30:in `process_action'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/actionpack-4.2.6/lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/activerecord-4.2.6/lib/active_record/railties/controller_runtime.rb:18:in `process_action'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/actionpack-4.2.6/lib/abstract_controller/base.rb:137:in `process'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/actionview-4.2.6/lib/action_view/rendering.rb:30:in `process'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/actionpack-4.2.6/lib/action_controller/test_case.rb:639:in `process'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/actionpack-4.2.6/lib/action_controller/test_case.rb:67:in `process'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/devise-3.5.6/lib/devise/test_helpers.rb:19:in `block in process'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/devise-3.5.6/lib/devise/test_helpers.rb:72:in `catch'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/devise-3.5.6/lib/devise/test_helpers.rb:72:in `_catch_warden'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/devise-3.5.6/lib/devise/test_helpers.rb:19:in `process'
# /Users/mary/.rvm/gems/ruby-2.3.0@website/gems/actionpack-4.2.6/lib/action_controller/test_case.rb:520:in `post'
# ./spec/controllers/process_faxes_controller_spec.rb:22:in `block (4 levels) in <top (required)>'
We've tried inserting binding.pry into the controller method to poke around ourselves, but whenever we try the call that's blowing up, we don't get any errors.
What could be causing FaxedDocumentProcessor.new to return a nil? And why can't we reproduce the error in pry?