While verifying doubles in RSpec is a good default, it is limited in the amount of methods it actually is able to verify.
The background is that RSpec can't verify dynamically defined methods, which is a
known issue
Show archive.org snapshot
for the usage of
helper_method
Show archive.org snapshot
and also the reason why
RSpec >= 3.6
Show archive.org snapshot
(see "Mocks: without_partial_double_verification") added without_partial_double_verification
.
This might be handy in case you are testing helpers in Rails, where you sometimes rely on methods defined in the application controller (e.g. current_user
and current_power
).
Example
class ApplicationController
def current_user
User.find_by(session[:user_id])
end
helper_method :current_user
end
module UsersHelper
def user_display_name
[current_user.first_name, current_user.last_name].join(' ')
end
end
Unit test with error
describe UsersHelper do
describe '#user_display_name' do
it 'returns the first and last name of a user' do
user = FactoryBot.create(:user)
allow(helper).to receive(:current_user).and_return(user)
expect(helper.user_display_name).to eq('Jim Knopf')
end
end
end
Error: <helper> does not implement: current_user
Solutions
RSpec >= 3.6 Unit test fixed with without_partial_double_verification
describe UsersHelper do
describe '#user_display_name' do
it 'returns the first and last name of a user' do
user = FactoryBot.create(:user)
without_partial_double_verification do
allow(helper).to receive(:current_user).and_return(user)
end
expect(helper.user_display_name).to eq('Jim Knopf')
end
end
end
RSpec < 3.6 Unit test fixed by defining and using verify_doubles as a spec config
Another approach would be to define a spec config, which can be turned off and on for each spec.
describe UsersHelper do
describe '#user_display_name', verify_doubles: false do
it 'returns the first and last name of a user' do
user = FactoryBot.create(:user)
allow(helper).to receive(:current_user).and_return(user)
expect(helper.user_display_name).to eq('Jim Knopf')
end
end
end
# In spec_helper.rb
RSpec.configure do |config|
config.around(:each, verify_doubles: false) do |example|
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = false
example.run
mocks.verify_partial_doubles = true
end
end
end
Note: This is just one over multiple options to solve the problem. You might also extract controller methods to helpers or pass in required objects as arguments.