ruby-on-rails - 我可以在 RSpec 测试中实现依赖注入(inject)吗?

标签 ruby-on-rails dependency-injection rspec

我正在重构我的测试。我心想,我应该将负责处理正确用户登录的逻辑和成功行为的逻辑分开。因此,我开始用我不成功的上下文创建一个共享示例,但我陷入了这一刻:

RSpec.shared_examples "changing status" do |arguments|
  /* ... */

  it_behaves_like "action requiring proper user logged in to be successful", action

  context "- when the required logged user is logged in" do
    before(:each) do
      /* ... */
    end
    context "and when the reservation has an allowed status" do
      /* ... */
    end
    context "and when the reservation has a not allowed status" do
      /* ... */
    end
  end
end
RSpec.shared_examples "action requiring proper user logged in to be successful" do |action|
  context "- when the logged in user is not the required logged user" do
    before(:each) do
      login(incidental_user)
    end
    it_behaves_like "unsuccessful attempt to change the reservation", action
  end
  context "- when there's no user logged in" do
    it_behaves_like "unsuccessful attempt to change the reservation", action
  end
end

因此,我想将上下文中的代码“当所需的登录用户登录时”注入(inject)到我的共享示例中以使其干净。我尝试使用匿名代码块和 yield 关键字来做到这一点:

RSpec.shared_examples "changing status" do |arguments|
  /* ... */

  it_behaves_like "action requiring proper user logged in to be successful", action do
    before(:each) do
      /* ... */
    end
    context "and when the reservation has an allowed status" do
      /* ... */
    end
    context "and when the reservation has a not allowed status" do
      /* ... */
    end
  end

end
RSpec.shared_examples "action requiring proper user logged in to be successful" do |action|
  context "- when the required logged user is logged in" do
    yield
  end
  context "- when the logged in user is not the required logged user" do
    before(:each) do
      login(incidental_user)
    end
    it_behaves_like "unsuccessful attempt to change the reservation", action
  end
  context "- when there's no user logged in" do
    it_behaves_like "unsuccessful attempt to change the reservation", action
  end
end

但不幸的是它得到了这个错误:

LocalJumpError: no block given (yield)

那么,我该怎么做呢?

最佳答案

有趣的问题。

您可以在一个封装的示例中完成此操作,但还有另一种在我看来更清晰的方法:

为正面和负面测试创建单独的shared_example。您已经得出了否定的结果,所以您很好(只需更改名称,以明确这是一组否定的测试)。

积极的一面可能是这样的:

RSpec.shared_examples 'restricted action with logged in user' do
  before { login(authorized_user) }

  specify do
    expect_stuff_typical_for_logged_in_user
    # e.g. expect(response).to be_success
  end
end

然后在您的规范中将其包含在 include_examples 中,像这样

context do 
  include_examples 'restricted action with logged in user'
  # you're "inside" the context of included examples so you can 
  # write down extra expectations specific for each action
end

可能存在这样的情况,您的积极部分没有共同的期望,只是设置上下文 - 您可以考虑使用 shared_context清楚地传达您的意图。

您可以将所有内容集中在一个共享示例中,如下所示:

RSpec.shared_examples "action requiring proper user logged in to be successful" do
  # set up the context for positive scenarios, so you can include it with 
  # `include_examples` and be "inside" this context
  before { login(authorized_user) }

  context "- when the logged in user is not the required logged user" do
    before(:each) do
      login(incidental_user)
    end
    it_behaves_like "unsuccessful attempt to change the reservation"
  end
  context "- when there's no user logged in" do
    before { log_out_people }
    it_behaves_like "unsuccessful attempt to change the reservation"
  end
end

这有两个问题。首先,你建立了一个积极的背景,然后你必须在消极的例子中撤销它(感觉 smelly )。 其次,规范中发生的事情可能并不明显。 它们看起来像这样:

context do
  include_examples 'action requiring proper user logged in to be successful'

  specify do
    expect(response).not_to be_redirect
  end

  context 'when user have not seen changes TOS' do
    before { }
    specify do
      expect(session[:notice]).to eq 'Please read new TOS'
    end
end 

而且根本不清楚负面例子是否被涵盖。

然后,如果在任何地方您需要对负面情况进行自定义期望 - 无论如何您都需要将它们分开。

您可以决定采用任何一种方式,但要注意权衡。

关于ruby-on-rails - 我可以在 RSpec 测试中实现依赖注入(inject)吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50588981/

相关文章:

ruby-on-rails - 如何在rails中将静态页面的输入保存到数据库

javascript - 在 Ruby on Rails 上构建 Javascript 对象数组的最佳方法

c# - 团结与委托(delegate)

php - 是否可以将路由参数传递给 Laravel 中的 Controller 构造函数?

javascript - AngularJS:如何在 AngularJS 中使用或注入(inject)第三方库

ruby-on-rails - 在使用 WebMock 时遇到问题,没有正确 stub

ruby-on-rails - Stubing 费加罗与 rspec

ruby-on-rails - capybara-webkit - rails session 未保留/设置

ruby-on-rails - 有没有办法用 rspec 检查内部方法变量?

ruby-on-rails - 我什么时候应该在 Cucumber 和 RSpec 工作流中单独测试 View ?