Ruby,Rspec和收益存根

时间:2018-09-12 09:19:35

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

假设我在Ruby中有一个这样的类:

class Test
  def execute
    count = 0
    40.times do
      search_for_names(count) do |name, last_name|
        yield name, last_name
      end
      count += 1
    end
  end

  def search_for_names(count)
    friend = get_friend_name(count)
    yield friend.name, friend.last_name
  end
end

我的问题是:如何在我的Rspec测试中存根我的search_for_names方法以获得40个不同的名称? (我安装了Faker)。 我尝试过:

let(:friends) do
described_class.new
end

allow(friends).to receive(:search_for_names).and_yield(
      Faker::Name.name,
      Faker::Name.last_name
)

 it 'finds multiple friends' do
    friends.execute do |name, last_name|
      puts name
      expect(name).not_to be_empty
      expect(last_name).not_to be_empty
    end
  end

但是它总是打印相同的名字x40。

然后...:

allow(friends).to receive(:search_for_names).and_yield(
      Faker::Name.name,
      Faker::Name.last_name
    ).and_yield(
      Faker::Name.name,
      Faker::Name.last_name
    )

但是它将打印两个不同的名称x40(80个名称)。但我只想使用40个不同的名字。可能吗 ? 预先感谢!

2 个答案:

答案 0 :(得分:1)

问题是.and_yield(Faker::Name.name, Faker::Name.last_name)被执行一次 。您的函数已经已准备好准备接收参数,请使用它:

40.times do |i|
  allow(friends).to receive(:search_for_names).with(i).and_yield(
    "#{Faker::Name.name}_#{i}",
    "#{Faker::Name.last_name}_#{i}"
  )
end

侧注:而不是引入局部变量count,而只需使用Integer#times传递给块的内容即可。

def execute
  40.times do |count|
    search_for_names(count) do |name, last_name|
      yield name, last_name
    end
  end
end

答案 1 :(得分:0)

另一种选择是像这样使用receive的块语法

allow(friends).to receive(:search_for_names) do |_,&block| 
  block.call(Faker::Name.name, Faker::Name.last_name)
end

我们不是捕获块yielding,而是捕获块(&block),然后使用Faker参数显式调用它。

这避免了每次调用allow时都需要执行40次内部循环来产生search_for_names实例的情况。

Repl Example