Rails / RSpec:上下文级别的memoized / cached块,例如before(:context)引用let

时间:2017-09-27 23:13:28

标签: ruby-on-rails ruby unit-testing rspec

在编写规范时,我经常会有一个昂贵的操作,我想测试多个方面而不需要每次都调用它。我怎么做,同时仍然引用更大的范围变量?

describe Hq::UsersController
  let(:create_params) {
    {'name': 'Bob',
    'email': 'bob@burgers.com'}
  }

  describe "#create" do
    context "when a user does not already exist" do
      before(:context) do
        # (some expensive operation here)
        VCR.use_cassette('external_user_check') do
          # note: this will error out, see message below
          post :create, :params => create_params
        end
      end

      it "creates the user and dependent objects" do
        expect(User.count).to be(1)
        user = User.first
        expect(user.name).to eq(create_params['name'])
      end

      it "returns an 204 (no content) status" do
        expect(response).to have_http_status(:no_content)
      end
    end

    context "when a user already exists" do
      before(:context) do
        User.create(email: create_params['email'])
      end

      it "raises a RecordInvalid error and does not create any objects" do
        VCR.use_cassette('external_user_check') do
          expect { post :create, :params => create_params }.to raise_error(ActiveRecord::RecordInvalid)
        end
        # I wish I could break this into two `it` blocks :(
        expect(User.count).to be(0)
      end
    end
  end
end

这是我得到的错误:

`let` and `subject` declarations are not intended to be called
 in a `before(:context)` hook, as they exist to define state that
 is reset between each example, while `before(:context)` exists to
 define state that is shared across examples in an example group.

我理解警告的意图,但在我的情况下,我们如何只运行或缓存一次昂贵的操作,同时还重复使用跨上下文的某些共享状态?通常,当我编写规范时,我认为状态在上下文中是相同的

现在,似乎我唯一的解决方案是将params复制并粘贴到多个context块中,以确保这一点。但是,如果参数变化或者参数冗长,维持成本会很高。

我愿意重构建议,或者这是否表明某些规范代码有异味。谢谢!

0 个答案:

没有答案