【问题标题】:How to stub env['warden'].user for ApplicationCable::Connection tests with rspec如何使用 rspec 为 ApplicationCable::Connection 测试存根 env['warden'].user
【发布时间】:2018-12-16 07:52:32
【问题描述】:

导轨 5.2 我有以下 ApplicationCable::Connection ruby​​ 文件:

module ApplicationCable
  class Connection < ActionCable::Connection::Base

    identified_by :current_user

    def connect
      self.current_user = find_verified_user
    end

    private

    def find_verified_user
      if verified_user = env['warden'].user
        verified_user
      else
        message = "The user is not found. Connection rejected."
        logger.add_tags 'ActionCable', message  
        self.transmit error: message 
        reject_unauthorized_connection
      end
    end
  end
end

我想测试此设置并使用以下 RSpec 测试:

require 'rails_helper.rb'

RSpec.describe ApplicationCable::Connection, type: :channel do

  it "successfully connects" do
    connect "/cable", headers: { "X-USER-ID" => 325 }
    expect(connection.user_id).to eq 325
  end
end

失败的原因是:

失败/错误:如果verified_user = env['warden'].user

无方法错误: nil:NilClass 的未定义方法“[]”

所以我想删除 env['warden'].user 代码并返回 325 的 id。 我尝试了以下方法:

allow(env['warden']).to receive(:user).and_return(325)

但这产生了以下错误:

undefined local variable or methodenv'

如何测试这个类?

【问题讨论】:

    标签: rspec devise rspec-rails actioncable


    【解决方案1】:

    试试这个:

    require 'rails_helper.rb'
    
    RSpec.describe ApplicationCable::Connection, type: :channel do
    
       let(:user)    { instance_double(User, id: 325) }
       let(:env)     { instance_double('env') }
    
      context 'with a verified user' do
    
         let(:warden)  { instance_double('warden', user: user) } 
    
        before do
          allow_any_instance_of(ApplicationCable::Connection).to receive(:env).and_return(env)
          allow(env).to receive(:[]).with('warden').and_return(warden)
        end
    
        it "successfully connects" do
          connect "/cable", headers: { "X-USER-ID" => 325 }
          expect(connect.current_user.id).to eq 325
        end
    
      end
    
      context 'without a verified user' do
    
        let(:warden)  { instance_double('warden', user: nil) }
    
        before do
          allow_any_instance_of(ApplicationCable::Connection).to receive(:env).and_return(env)
          allow(env).to receive(:[]).with('warden').and_return(warden)
        end
    
        it "rejects connection" do
          expect { connect "/cable" }.to have_rejected_connection
        end
    
      end
    end
    

    【讨论】:

    • 感谢您的代码。我试过这个并得到以下错误: NameError: uninitialized constant Connection
    • 已更新。 Connection 应该是 ApplicationCable::Connection。而且,我修复了 env 模拟的另一个问题。
    • 我进行了更改,现在我得到 ApplicationCable::Connection does not implement: env
    • 我已经使用我从您的答案中修改的代码编辑了您的答案以通过测试。我还不知道如何解决难闻的 allow_any_instance_of 部分。这两个测试现在按预期通过了。我希望你不介意我编辑你写的代码。
    • 很高兴你能成功!而且,我很高兴能够提供帮助!我不会担心气味。控制器(显然是电缆)是出了名的难以模拟,因为 Rails 控制实例化,所以你不能注入测试替身。这就是为什么 RSpec 有allow_any_instance_of
    【解决方案2】:

    这里有一个很好的解释你的问题https://stackoverflow.com/a/17050993/299774

    问题是关于控制器测试的,但实际上非常相似。

    我也不认为您应该在控制器中访问低级别的env['warden']。如果 gem 的作者决定改变它——你必须修复你的应用程序。 可能用这个配置初始化了守望者对象,并且应该有一个可用的对象(只是在运行规范时不需要 - 如上面的链接中所述)。

    【讨论】:

    • 对不起 - 我一直提到控制器,这是关于动作电缆的。但从概念上讲,它们是同一层,因此 IMO 我们可以使用控制器的“概念”来讨论它们。
    • 感谢元。我已经根据sitepoint.com/… 等许多网站上概述的做法设置了我的 ApplicationCable::Connection。我只是想知道是否有办法通过删除这个方法来测试它。我认为您发送的链接是相关的,并且可能是我无法进行此测试的原因。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-04
    • 1970-01-01
    • 1970-01-01
    • 2011-12-08
    • 2012-03-09
    相关资源
    最近更新 更多