对于在RSpec中使用接收匹配器的示例,是否有任何方法可以设置公共代码块(即在每个';之前设置一个';)?

对于在RSpec中使用接收匹配器的示例,是否有任何方法可以设置公共代码块(即在每个';之前设置一个';)?,rspec,Rspec,下面是一个用例示例,我们正在测试,以确保晚餐桌#arrange仅在安排客人时调用另一个方法晚餐桌#moar_椅子 describe DinnerTable do subject(:table) { DinnerTable.new } describe "#arrange" do context "when arranging for family" do let(:group) { :family } it "doesn't get extra chai

下面是一个用例示例,我们正在测试,以确保
晚餐桌#arrange
仅在安排客人时调用另一个方法
晚餐桌#moar_椅子

describe DinnerTable do
  subject(:table) { DinnerTable.new }

  describe "#arrange" do
    context "when arranging for family" do
      let(:group) { :family }
      it "doesn't get extra chairs" do
        expect(table).not_to receive(:moar_chairs)
        table.arrange(group)
      end
    end

    context "when arranging for guests" do
      let(:group) { :guests }
      it "gets extra chairs" do
        expect(table).to receive(:moar_chairs)
        table.arrange(group)
      end
    end
  end
end
注意上下文如何设置要安排的组(家庭或客人),但我们仍然在每个示例中单独调用相关方法,
arrange
(使上下文变得有些毫无意义)

通常情况下,将该方法放在
之前的
块中会起作用,因为大多数匹配器都期望当前的可测试条件,但由于我们使用
接收
匹配器,它期望将来会发生一些事情,所以我们不能这样做,否则测试将失败。将其放入
after
块也会失败,因为在执行
after
块之前,预期返回false。如果我们在
期间有某种
块在示例结束之前运行就好了

describe DinnerTable do
  subject(:table) { DinnerTable.new }

  describe "#arrange" do
    during { table.arrange(group) }

    context "when arranging for family" do
      let(:group) { :family }
      it { should_not receive(:moar_chairs) }
    end

    context "when arranging for guests" do
      let(:group) { :guests }
      it { should receive(:moar_chairs) }
    end
  end
end
(或者它可以被称为
动作
谓词
,与
主语
一起使用?另一种选择是在让接收匹配器失败之前运行after块……但我不知道会产生什么样的其他后果


对于使用
receive
matchers为多个示例设置公共块,是否还有其他好的模式?

在执行测试代码之前,需要设置
receive
期望值。以下将起作用并消除一些重复(
DinnerTable
class definition仅供说明之用):


哦,我错了!我第一次一定是做错了什么,因为在块之后将该方法放入
,确实有效:D耶

因此:

更新

或者,为了获得更好的语义,添加一个名为action的spec helper方法,如下所示:

def action(&block)
  shared_context "run action before", run_action: :first do
    before(&block)
  end
  shared_context "run action after", run_action: :last do
    after(&block)
  end
end
然后这些例子看起来像:

describe DinnerTable do
  subject(:table) { DinnerTable.new }

  describe "#arrange", run_action: :last do
    action { table.arrange(group) }

    context "when arranging for family" do
      let(:group) { :family }
      specify { table.should_not receive(:moar_chairs) }
    end

    context "when arranging for guests" do
      let(:group) { :guests }
      specify { table.should receive(:moar_chairs) }
    end
  end
end

哦,对不起,我在接收匹配器之前打电话给arrange是一个错误修正了!:)但是是的,这比(现在修正了)稍微好一点原始模式…似乎arrange的调用应该可以设置为Descripte块的上下文,不可能的唯一原因是因为我们碰巧使用了receive matcher…关于这一点,我有点不对劲。您的初始版本有点长,重复性更高,但意图是这很容易辨别。是的……确实如此。但是我觉得对于描述简单方法的描述块,应该有一种方法来定义您正在描述的方法一次,然后有几个示例来对该方法的工作原理做出各种断言-就像您可以设置
主题一次并全部使用它一样示例。它可能是
谓词
。但彼得定义
谓词
的方法可能更易于维护/重用,等等。
def action(&block)
  shared_context "run action before", run_action: :first do
    before(&block)
  end
  shared_context "run action after", run_action: :last do
    after(&block)
  end
end
describe DinnerTable do
  subject(:table) { DinnerTable.new }

  describe "#arrange", run_action: :last do
    action { table.arrange(group) }

    context "when arranging for family" do
      let(:group) { :family }
      specify { table.should_not receive(:moar_chairs) }
    end

    context "when arranging for guests" do
      let(:group) { :guests }
      specify { table.should receive(:moar_chairs) }
    end
  end
end