2011-02-16 2 views
1

나는 기존 MySQL 데이터베이스 테이블에 기본 키를 만들어야하는 루비 코드를 만들고있다.첫 번째 호출에서 예외를 발생시키는 메소드를 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의 블록 형식이 여기에서 작동 할 수도 있지만 가능하면 깨끗한 방법으로 처리하고 싶습니다.

아이디어가 있으십니까?

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 

그것은 주석에 말씀합니까 ​​:

답변

1

나는 루비 (일반적으로) The Principle of Least Astonishment을 준수하기 때문에, 하나 그냥 말이 무엇을 시도하고 무슨 일이 일어 나는지 것을 잊어 버렸습니다. :)

관련 문제