Home > Software engineering >  Rails stub method on initialized ActiveRecord object
Rails stub method on initialized ActiveRecord object

Time:02-05

I want to stub set_user_tokens which is executed on the initialized (not saved) ActiveRecord object. This method assigns a token to the login object.

class AwareLogin < Authenticatable
  def authenticate!
      login = Login.find_or_initialize_for_authentication(params[:login][:email], 'aware')
      class << login
        include AwareAuth
      end

      if login.valid_password?(password) || (set_token = login.id.nil? && aware_response.success?)
        login.set_user_tokens(aware_response) if set_token
        success!(login)
      else
        aware_response.success? ? fail!(:aware_auth) : raise(ActiveRecord::Rollback)
      end
    end
  end
end

So I want to stub setu_user_tokens method:

    login.set_user_tokens(aware_response) if set_token

to receive login ActiveRecord object with attributes of oauth_tokens like below:

login.oauth_token
=> {"access_token" => return_token,"refresh_token" => nil,"token_expiration" => 1200 }

I've tried:

      allow_any_instance_of(Login).to receive(:set_user_tokens).with(status: 200, body: { access_token: return_token }.to_json, success?: true).and_return(
        oauth_tokens: {
          "access_token" => return_token,
          "refresh_token" => nil,
          "token_expiration" => 1200 },
      )

But I'm getting an error:

Login does not implement #set_user_tokens

CodePudding user response:

I would be willing to bet your issue is set_user_tokens is part of AwareAuth.

Since you are only including this module in the eigenclass of the instance (login) as part of the AwareLogin#authenticate! method, the Login class does not implement that method at any point in time.

Is there a reason you are doing it this way rather than just including AwareAuth in the Login class in the first place?

Either way, while your question appears to lack context for the test itself, if I understand correctly, we should be able to resolve these issues as follows:

it 'sets user tokens' do 
  login = Login
    .find_or_initialize_for_authentication('[email protected]', 'aware')
    .tap {|l| l.singleton_class.send(:include, AwareAuth) }
  allow(Login).to receive(:find_or_initialize_for_authentication).and_return(login) 
  allow(login).to receive(:set_user_tokens).and_return(
        oauth_tokens: {
          "access_token" => return_token,
          "refresh_token" => nil,
          "token_expiration" => 1200 }
      )
  #perform your action and expectations here
end

By using partial doubles you can stub the specific methods you need to without impacting any other functionality of the object itself.

  •  Tags:  
  • Related