Ответ 1
Вы можете использовать and_yield, чтобы rspec вызывал блок, переданный макету:
MyClass.stub(:find_each).and_yield(one_mock).and_yield(two_mock)
Мне было интересно, как проверить вызов find_each в rspec. Я привык просто останавливать то, что хочу, чтобы мои модели возвращались, поэтому я не полагаюсь на тестовые данные в db следующим образом:
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])
в тесте spec, часть "do stuff here" не выполняется. Кто-нибудь знает, как заглушить find_each для тестирования rspec?
Вы можете использовать and_yield, чтобы rspec вызывал блок, переданный макету:
MyClass.stub(:find_each).and_yield(one_mock).and_yield(two_mock)
Весь смысл прерывания метода заключается в том, что метод возвращает ожидаемое значение и не выполняет его содержимое. Если у вас есть куча логики в методе 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
Это должно сделать это:
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]
}