Rails 已初始化 ActiveRecord 对象的存根方法

Rails stub method on initialized ActiveRecord object

我想存根 set_user_tokens,它在初始化(未保存)的 ActiveRecord 对象上执行。此方法将标记分配给 login 对象。

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

所以我想存根 setu_user_tokens 方法:

    login.set_user_tokens(aware_response) if set_token

接收具有 oauth_tokens 属性的登录 ActiveRecord 对象,如下所示:

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

我试过:

      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 },
      )

但是我收到一个错误:

Login does not implement #set_user_tokens

我敢打赌你的问题 set_user_tokensAwareAuth 的一部分。

由于您仅将此模块作为 AwareLogin#authenticate! 方法的一部分包含在实例 (login) 的特征 class 中,因此 Login class 不会在任何时间点实现该方法。

您这样做是否有原因,而不是首先将 AwareAuth 包含在 Login class 中?

无论哪种方式,虽然您的问题似乎缺乏测试本身的上下文,但如果我理解正确,我们应该能够按如下方式解决这些问题:

it 'sets user tokens' do 
  login = Login
    .find_or_initialize_for_authentication('some_email@example.com', '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

通过使用部分双打,您可以存根您需要的特定方法,而不会影响对象本身的任何其他功能。