我可以在RSpec测试中实现依赖注入吗?

时间:2018-05-29 16:28:39

标签: 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

所以,我想将我的上下文"when the required logged user is logged in"中的代码注入到我的共享示例中,以使其干净。我尝试使用匿名代码块和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:没有给定块(yield)

那么,我该怎么做呢?

2 个答案:

答案 0 :(得分:0)

有趣的问题。

你可以在一个封装的例子中做到这一点,但还有另一种,IMO更清晰的方式:

为正面和负面测试单独shared_example s。你已经解决了这个问题,所以你做得很好(只需更改名称,明确它是一组负面的测试)。

积极的人可以这样:

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 

它根本不清楚,负面的例子都被涵盖了。

然后,如果在任何地方你需要对否定案例的自定义期望 - 你仍然需要拆分它们。

您可以决定以任何一种方式了解权衡。

答案 1 :(得分:0)

最后我用lambda解决了我的问题:

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

  it_behaves_like "action requiring proper user logged in to be successful", action, -> {
    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
RSpec.shared_examples "action requiring proper user logged in to be successful" do |action, successful_behavior|
  context "- when the required logged user is logged in" do
    successful_behavior.()
  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