Stubowanie tylko pierwszego wywołania metody

Witam.
Sprawa wygląda tak , że po utworzeniu rekordu, generuje mu numer , sprawdzam w kilku roznych tabelach czy zaden z rekordół nie ma tego numeru , po czym jezeli któryś ma , generuje nowy losowy numer i znowu sprawdzam - az nie znajde ‘wolnego’ numeru.
Chciałbym to przetestować więc chciałem zrobić tak:

MyModel.stub(:rand_number).and_return('123456', 6.times.map{rand(10)}.join('')}) Problem tylko jest tego typu, ze blok (2gi argument and_returna) podany jako wartosc którą ma zwracać rand_number wykonuje się w trakcie stubowania a nie w trakcie wywolania tej metody. Także ustawia się jedna wartość dla wszystkich kolejnych wywołań. W jaki sposób mogę zestubować to tak , żeby ten blok wykonywał się podczas wywołania metody rand_number?

Pozdrawiam

użyć bloku? ty po prostu przekazałeś wartość (dlatego wywołuje się ona raz)

MyModel.stub(:rand_number).and_return do Array.new(6) { rand 10 }.join end

Ugh faktycznie. Dzięki wielkie. Z początku próbowałem też z blokiem, ale bez sensu wywołując na nim .call ;/

Upsa sa. Jednak nie do końca to działa tak jakbym to sobie wymarzył. Tzn przykład który podałeś - owszem działa bez zarzutu. Ale gdy chce tak jak opisywałem wcześniej najpierw podac 1szy argument jako string (numer który już jest w bazie i chce przetestowac ze sie nie ustawi taki numer) , a jako drugi blok, to blok się nie wykonuje tylko wystubowana funkcja zwraca: #Proc:0x0000000a7b9d50@/home/sarin/projects/mojprojekt/spec/models/mojtest_spec.rb:12.

Pokaż test.

Po tym co napisałeś odnoszę wrażenie, że chcesz w jednym teście wywoływać to dwa razy, żeby dwie różne rzeczy sprawdzać. Jeśli tak, to jest to źle napisany test. Pamiętaj o zasadzie:

c1 = FactoryGirl.create(:calculation, name: "ABC12123124") p = FactoryGirl.create(:policy, number: "POL12123123") Calculation.stub!(:rand_number).and_return('123124', '123123', 6.times.map{ Random.rand(10) }.join('') ) c2 = FactoryGirl.create(:calculation) c2.name.should_not == 'OFR12123124' c2.name.should_not == 'OFR12123123' c2.name.length.should == 11
Test ogólnie działa, ale przy całej tej akcji zacząłem się zastanawiać czemu ten blok mi nie działa tak jakbym chciał. Paweł Kondzior mi już wytłumaczył , że and_return docelowo wcale nie miało przyjmować bloków , ale przypadkiem to działa w niektórych wersjach rspeca ;p
Chyba spróbuje użyć Calculation.should_receive(:rand_number).exactly(3).times, aby sprawdzic ze po dopiero 3cie wywolanie tej funkcji które to nie zwrociło istniejącego numeru ustawiło mi ten numer - bo tak naprawde to wlasnie to chcialem w tym tescie przetestować.

A co do zasady jeden test - jedna asercja - faktycznie jak teraz przeglądam swoje testy to troche obca mi ona była ;]

Na podstawie posiadanej ubogiej wiedzy na temat domeny Twojego problemu ja bym raczej napisał coś takiego:

[code]describe Calculation do
it ‘should not have a number as an existing Policy’ do
FactoryGirl.create :policy, number: “POL12123123”
Calculation.stub!(:rand_number).and_return(‘123123’)
calculation = Calculation.new

calculation.name.should_not == 'OFR12123123'

end

it ‘should not have a number as an existing Calculation’ do
FactoryGirl.create :calculation, number: “POL12123123”
Calculation.stub!(:rand_number).and_return(‘123123’)
calculation = Calculation.new

calculation.name.should_not == 'OFR12123123'

end

it ‘should have a random name’ do
Calculation.mock!(:rand_number).and_return(‘123123’)
calculation = Calculation.new

calculation.name.should == 'OFR12123123'

end

describe ‘should re-run the rand_number in case of an exisiting result’ do
Calculation.stub!(:rand_number).and_return(‘123123’, ‘234567’)
Calculation.should_receive(:rand_number).exactly(2).times
FactoryGirl.create :calculation, number: “POL12123123”

calculation = Calculation.new

end
end[/code]
Poza “jeden test - jedna asercja” jeszcze jedna sprawa: nie powinieneś raczej testować jak wyglądają obiekty stworzone przez FactoryGirl, tylko jak wyglądają obiekty stworzone normalną inicjalizacją.