Reputation: 1133
I've got a method defined in ApplicationController as a helper method.
helper_method :can_access_participant_contact_data?
I'm trying to write a test for a helper method that resides in a helper file. This helper method makes a call to helper_method :can_access_participant_contact_data?
# In participants_helper.rb
#
def redacted_contact_data participant, attribute_name
attribute = participant.try(:contact_data).try(attribute_name)
return attribute if can_access_participant_contact_data?(participant)
return nil if attribute.blank?
return attribute.gsub(/\S/i, '*') # Asterisked string
end
All I'm doing so far in my test is making a call to redacted_contact_data
require 'test_helper'
class ParticipantsHelperTest < ActionView::TestCase
test "should return an asterisked string with spaces" do
redacted_contact_data(Participant.first, :name)
end
end
When I run my test, I'm getting this message
undefined method `can_access_participant_contact_data?' for #<ParticipantsHelperTest:0x007fd6c7c6d608>
I've been having a look around but I'm not sure how to get around this issue. Do I need to mock can_access_participant_contact_data?
somehow? or can I just include the method into the test?
Upvotes: 5
Views: 3115
Reputation: 1199
Another idea is to do "helper test" in "controller test" as follows:
require 'test_helper'
class ParticipantsControllerTest < ActionController::TestCase
setup do
# do some initialization here. e.g. login, etc.
end
test "should return an asterisked string with spaces" do
participant = ...
get :show, id: participant.id
assert_equal '...', @controller.view_context.redacted_contact_data(...)
end
end
Where, @controller is ParticipantsController object already defined by rails controller testing framework (or you can explicitly define it when controller name is different from *ControllerTest), and view_context is the object for helper methods (see https://api.rubyonrails.org/classes/ActionView/Rendering.html#method-i-view_context for more detail).
Helper method often refer controller object and/or method (like session, request) so that it is sometimes difficult to do unit-test only in test/helpers/*. This is the reason why I test helper in controller in such a case.
Upvotes: 0
Reputation: 6603
AFAIK (As far as I know), you cannot fix this without stubbing, or doing some change in your code, as essentially a helper file is just a module of itself that should be treated independent of where it's gonna be included. Who knows you might want to include such helper file inside your model files for example, in which incidentally the model file also has a method named can_access_participant_contact_data?
but does differently from that one defined in the ApplicationController
, therefore you cannot unit test this without specifying the context / base.
Stubbing:
Or manually (maybe there's a better way) by:
test "should return an asterisked string with spaces" do
ParticipantsHelper.class_eval do
define_method :can_access_participant_contact_data? do |arg|
true
end
end
redacted_contact_data(Participant.first, :name)
end
Or, moving all your ApplicationController
helper methods into a separate/existing helper file, say inside your already existing ApplicationHelper
. Then afterwards, include that helper inside your other helper file that you are testing that is making use of the method/s. i.e.:
# helpers/application_helper.rb
module ApplicationHelper
def can_access_participant_contact_data?(participant)
# YOUR CODE
end
end
# helpers/participants_helper.rb
module ParticipantHelper
include ApplicationHelper
def redacted_contact_data participant, attribute_name
attribute = participant.try(:contact_data).try(attribute_name)
return attribute if can_access_participant_contact_data?(participant)
return nil if attribute.blank?
return attribute.gsub(/\S/i, '*') # Asterisked string
end
end
If using this approach, then two ways to call the helper method inside the controller:
Use Rails helpers
method inside a controller:
class ParticipantsController
def show
helpers.can_access_participant_contact_data?(@participant)
end
end
Or, include the helpers directly (I personally prefer the other approach just above)
class ApplicationController < ActionController::Base
include ApplicationHelper
end
class ParticipantsController < ApplicationController
def show
can_access_participant_contact_data?(@participant)
end
end
For the view files, you won't need to update any code.
Upvotes: 3