【问题标题】:RSpec how to stub out yield and have it not hit ensureRSpec如何存根产量并确保它不会命中
【发布时间】:2018-12-09 01:04:58
【问题描述】:

我有一个名为 set_current_user 的环绕 action_action

def set_current_user
  CurrentUser.set(current_user) do
    yield
  end
end

在 CurrentUser 单例中

  def set(user)
    self.user = user
    yield
  ensure
    self.user = nil
  end

我不知道如何将产量存根,并且没有调用方法的确保部分

理想情况下,我想做类似的事情

it 'sets the user' do
  subject.set(user)
  expect(subject.user).to eql user
end 

我遇到了两个错误

    1. 没有给出块
    1. 当我通过一个块时,self.user = nil 会被调用

提前致谢

【问题讨论】:

标签: ruby unit-testing rspec rspec-rails


【解决方案1】:

指出一些可能会有所帮助的事情:

ensure 保留用于无论发生什么情况都希望运行的代码块,因此您的self.user 将始终为nil。我认为您想要的是在出现异常时将 user 分配给 nil 。在这种情况下,您应该改用rescue

def set(user)
  self.user = user
  yield
rescue => e
  self.user = nil
end

至于单元测试,您想要的只是测试CurrentUser 类中的.set 方法。假设您的周围过滤器中的所有内容都正确连接,这里有一个可能适合您的示例:

describe CurrentUser do
  describe '.set' do
    let(:current_user) { create(:user) } 
    subject do
      CurrentUser.set(current_user) {}
    end
    it 'sets the user' do
      subject
      expect(CurrentUser.user).to eq(current_user)
    end 
  end
end

希望这会有所帮助!

【讨论】:

  • 感谢您的回复我没有提到我需要在每次请求后清除用户。我在下面发布了一个答案,我承认这有点奇怪,但确实完成了工作。
【解决方案2】:

我不确定你打算用这个完成什么,因为你似乎只是想确保在块中设置 user 并在之后取消设置。如果是这种情况,那么以下应该可以正常工作

class CurrentUser
  attr_accessor :user
  def set(user)
    self.user = user
    yield
  ensure
    self.user = nil
  end
end

describe '.set' do
  subject { CurrentUser.new }
  let(:user) { OpenStruct.new(id: 1) }
  it 'sets user for the block only' do 
    subject.set(user) do 
      expect(subject.user).to eq(user)
    end 
    expect(subject.user).to be_nil 
  end
end

这将检查在块内部(调用 yield 的地方)subject.user 等于 user 并且之后 subject.user 为零。

输出

.set
  sets user for the block only

Finished in 0.03504 seconds (files took 0.14009 seconds to load)
1 example, 0 failures

【讨论】:

    【解决方案3】:

    我没有提到我需要在每次请求后清除用户。

    这就是我想出的。将期望放在 lambda 中有点疯狂,但确实确保在处理请求之前设置用户并在之后清除它

    describe '.set' do
      subject { described_class }
    
      let(:user) { OpenStruct.new(id: 1) }
    
      let(:user_expectation) { lambda{ expect(subject.user).to eql user } }
    
      it 'sets the user prior to the block being processed' do
        subject.set(user) { user_expectation.call }
      end
    
      context 'after the block has been processed' do
        # This makes sure the user is always cleared after a request
        # even if there is an error and sidekiq will never have access to it.
    
        before do
          subject.set(user) { lambda{} }
        end
    
        it 'clears out the user' do
          expect(subject.user).to eql nil
        end
      end
    end
    

    【讨论】:

      猜你喜欢
      • 2019-02-16
      • 2013-08-08
      • 1970-01-01
      • 2021-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多