Как я могу заглушить find_each для тестирования rspec в rails 3 - PullRequest
36 голосов
/ 08 декабря 2010

Мне было интересно, как проверить вызов find_each в rspec.Я привык просто задавать то, что я хочу, чтобы мои модели возвращали, поэтому я не полагаюсь на тестовые данные в БД, как это:

MyClass.stub(:find).and_return(my_mock)

Однако в другом классе я делаю это:

MyClass.find_each do |instance_of_my_class|
  do_stuff_here_on(instance_of_my_class)
end

Я обнаружил, что если я сделаю это:

MyClass.stub(:find_each).and_return([one_mock, two_mock])

в тесте спецификации, то часть "сделай здесь" не будет выполнена.Кто-нибудь знает, как заглушить find_each для тестирования rspec?

Ответы [ 4 ]

44 голосов
/ 08 декабря 2010

Вы можете использовать and_yield, чтобы rspec вызывал блок, передаваемый в макет:

MyClass.stub(:find_each).and_yield(one_mock).and_yield(two_mock)
2 голосов
/ 08 декабря 2010

Смысл заглушки метода заключается в том, что метод возвращает ожидаемое значение, а не выполняет его содержимое. Если у вас есть набор логики в методе find_each, я бы рекомендовал перенести его в отдельный метод и протестировать эту логику отдельно. Затем вы можете проверить, что ваш метод вызывается во время выполнения.

Вот пример довольно высокого уровня:

class Example1
  def my_method
    # some logic
  end
end

class Example2
  def my_other_method
    Example1.find_each(&:my_method)
  end
end

Rspec:

describe Example1 do
  it "should return something" do
    example = Example1.new
    example.my_method.should == something
  end
end

describe Example2 do
  it "should call my_method on Example1" do
    example1 = mock(:example1, :my_method => true)
    example2 = Example2.new

    example1.should_receive(:my_method)
    example2.my_other_method
  end
end
1 голос
/ 01 октября 2018

Если вам нужно заглушить find_each в проверенном двойнике и сделать так, чтобы он прошел через определенный массив значений, вы можете сделать это:

let(:my_relation_with_mocked_find_each) do
  relation = instance_double('YourModel::ActiveRecord_Relation')

  receive_yield = receive(:find_each)

  fake_objs.each do |obj|
    receive_yield = receive_yield.and_yield(obj)
  end

  allow(relation).to receive_yield
  relation
end
1 голос
/ 21 ноября 2011

Это должно сделать это:

MyClass.stub(:find_each) {|block|
  block.call
  [one_mock, two_mock]
}

Если do_stuff_here_on не доступен глобально, например, метод экземпляра для some_object , вам понадобится instance_evalчтобы получить правильную область для блока:

MyClass.stub(:find_each) {|block|
  some_object.instance_eval(&block)
  [one_mock, two_mock]
}
...