Reputation: 296
I'm currently working on a team that requires 100% code coverage and I cannot for the life of me get hit this single line method to get my current coverage up to 100%.
I have a base controller that looks like this which multiple other controller extend from.
module Owners
module Pets
class BaseController < Owners::ApplicationController
private
def current_pet
current_owner.all_pets.find(params[:pet_id])
end
end
end
end
My spec for this controller looks like this.
require 'rails_helper'
Rails.describe Owners::Pets::BaseController, type: :controller do
routes { Owners::Engine.routes }
controller Owners::Pets::BaseController do
def index
current_pet
end
end
let(:user) { double :user, id: 1, owner: nil }
before { sign_in(user) }
before do
allow(request.env['warden']).to receive(:user).and_return user
allow(Owners::User).to receive(:find).with(user.id).and_return user
end
context 'with current owner and pet' do
let(:owner) { create :owner }
let(:pet) { create(:owner_pet, owner: owner) }
describe '#current_pet' do
before do
allow(controller).to receive(:current_pet).and_return pet
routes.append { get 'index' => 'owners/pets/base#index' }
end
it do
get :index
is_expected.to eq pet
end
end
end
end
The spec is failing with the error "No route matches {:action=>"index", :controller=>"owners/pets/base"}" Routes.append should add the proper route, correct?
Update: By moving my routes { Owners::Engine.routes }
line above the anonymous controller it no longer throws an error related to routes. However now it is comparing pet
with the actual controller class. The output is too long to paste here but it's essentially:
expected: #<Owners::Pet>
got: #<#<Class:0x007fc65c860518>:0x007fc65f83a248>
with a whole bunch of attributes and methods.
Upvotes: 1
Views: 1485
Reputation: 11076
This test has no value. You're stubbing the very method that you're testing. Even if the method body of #current_pet
raised an exception, the test would still pass.
Generally, it's best to avoid testing private methods directly. You should be able to test this method indirectly via one of the classes which inherits from Owners::Pets::BaseController
.
Upvotes: 1
Reputation: 7434
When you use the syntax it { is_expected.to ... }
Rspec must infer what "it" is based on the test itself. The subject
method can be used to explicitly specify what "it" is; in cases where subject
is not present, Rspec will instantiate a new instance of the class which is being tested. In your case that would be the controller itself.
Try setting the subject
explicitly inside the context of the #current_pet
block.
For example,
context 'with current owner and pet' do
let(:owner) { create :owner }
let(:pet) { create(:owner_pet, owner: owner) }
describe '#current_pet' do
before do
allow(controller).to receive(:current_pet).and_return pet
routes.append { get 'index' => 'owners/pets/base#index' }
end
# set this to whatever you want "is_expected.to" to be
subject { controller.current_pet }
it do
get :index
is_expected.to eq pet
end
end
end
Obligatory Note: I have to agree with other posters that this test is not very useful. Conventional wisdom is to only test public methods (private methods get tested by their usage within a public method).
Upvotes: 0