2011-02-16 30 views
1

我正在研究一些需要在現有MySQL數據庫表上創建主鍵的Ruby代碼。它需要檢測和修復重複,允許索引創建成功,以下算法:我可以FlexMock方法在第一次調用時引發異常,然後在第二次調用時返回有效的對象嗎?

# 1. Query 
ALTER TABLE foo ADD PRIMARY KEY (id) 
# 2. Handle exception: 
Duplicate entry '3761290' for key 'PRIMARY' (Mysql::Error) 
# 3. Query: 
SELECT COUNT(1) FROM TABLE foo WHERE id = 3761290 
# 4. (Assuming 5 rows were returned from the previous query) Query: 
DELETE FROM TABLE foo WHERE id = 3761290 LIMIT 4 OFFSET 1 
# 5. retry ALTER TABLE query 

測試看起來是這樣的:

def test_create_primary_key 
    table = 'foo' 
    db = flexmock 
    db.should_receive(:prepare). 
     with("ALTER TABLE #{table} ADD PRIMARY KEY (id)"). 
     twice. 
     and_raise(Mysql::Error, "Duplicate entry '3761290' for key 'PRIMARY'") 
    db.should_receive(:prepare). 
     with("SELECT COUNT(1) FROM #{table} WHERE id = ?"). 
     once. 
     and_return(MockStatement.new [ [5] ]) 
    db.should_receive(:prepare). 
     with("DELETE FROM #{table} WHERE id = ? LIMIT 4 OFFSET 1"). 
     once. 
     and_return(MockStatement.new [ [5] ]) 

    indexer = Indexer.new :database_handle => db 
    indexer.create_indexes table 
end 

的問題是,代碼將在運行無限循環(除非它有最大重試條件,它可能會這樣做),因爲它將繼續從FlexMock的db中獲得異常。

理想情況下,模擬應該能夠在第一次引發異常,然後第二次返回有效的語句句柄。 #with的塊形式可能在這裏工作,但我想盡可能以乾淨的方式來完成。

任何想法?

回答

1

我忘了,因爲紅寶石(一般)符合The Principle of Least Astonishment,應該只是嘗試情理之中的事情,看看會發生什麼:

def test_yield_then_return 
    mock = flexmock 
    flexmock(mock).should_receive(:foo). 
     with(:bar). 
     and_raise(RuntimeError). 
     and_return(true) 

    assert_raises(RuntimeError) { mock.foo :bar } 
    assert mock.foo(:bar) 
    end 

做什麼它在錫說。 :)

相關問題