2014-12-24 59 views
2

我目前正在編寫一個與竹構建服務器交互的小lib。測試使用pytest完成。我被困在以下問題。我想測試一個while循環,直到某些狀態滿足爲止。閱讀pytest文檔,我試圖「嘲笑」/ monkeypatch的狀態,但它並沒有真正的工作。我可能做一些基本的錯誤在這裏: 這是有問題的,而循環:如何使用pytest測試無限while循環

# determine current status 
    running = self._is_a_build_running() 

    # turn on and off running powerplug while building 
    while running: 
     self.feedback.turn_off_success() 
     self.feedback.turn_on_running() 
     time.sleep(self.blinker_time) 
     self.feedback.turn_off_running() 
     self._update_builds_status() 
     running = self._is_a_build_running() 

所以我試着用pytest是創造一個夾具,用於積極的,像這樣的負面_is_a_build_running

@pytest.fixture(scope='function') 
def mock_is_a_build_running(): 
    return False 

然後使用這個測試方法使用ThreadPool(在這裏解釋how to get the return value from a thread in python?),因爲我也需要包含while循環的方法的結果。

def test_update_status_running(bamboopickups, monkeypatch, 
        mock_update_overall_data_positive, 
        mock_update_builds_status_positive, 
        mock_is_a_build_running): 
monkeypatch.setattr('BambooPickup._update_overall_data', lambda x: mock_update_overall_data_positive) 
monkeypatch.setattr('BambooPickup._update_builds_status', lambda x: mock_update_builds_status_positive) 

pool = ThreadPool(processes=1) 
async_result = pool.apply_async(bamboopickups.update_status()) 

monkeypatch.setattr('BambooPickup._update_overall_data', lambda x: mock_update_overall_data_positive) 
monkeypatch.setattr('BambooPickup._is_a_build_running', lambda x: mock_is_a_build_running) 

actual = async_result.get() 
expected = True 
assert actual == expected 

這可能是很容易與pytest-模擬完成,但到目前爲止,我只使用此處描述的首選方式:http://pytest.org/latest/monkeypatch.html

回答

3

因此,經過一些更深入的研究,我發現了一個解決方案,現在滿足我。我想分享它,以防其他人遇到同樣的問題。其實這是很簡單的,並與https://gist.github.com/daltonmatos/3280885一些輔助類,我想出了以下testcode:

def test_update_status_running(bamboopickup, monkeypatch, 
           mock_update_overall_data_positive, 
           mock_update_builds_status_positive): 
    monkeypatch.setattr('pickups.bamboo.bamboopickup.BambooPickup._update_overall_data', lambda x: mock_update_overall_data_positive) 
    monkeypatch.setattr('pickups.bamboo.bamboopickup.BambooPickup._update_builds_status', lambda x: mock_update_builds_status_positive) 

    with mock.patch.object(bamboopickup, '_is_a_build_running') as mockfoo: 
     mockfoo.return_value = AlmostAlwaysTrue(2) 
     bamboopickup.update_status() 

和輔助類:

class AlmostAlwaysTrue(object): 
    def __init__(self, total_iterations=1): 
     self.total_iterations = total_iterations 
     self.current_iteration = 0 

    def __nonzero__(self): 
     if self.current_iteration < self.total_iterations: 
      self.current_iteration += 1 
      return bool(1) 
     return bool(0) 

    # Python >= 3 
    def __bool__(self): 
     if self.current_iteration < self.total_iterations: 
      self.current_iteration += 1 
      return bool(1) 
     return bool(0) 

人們還可以修改它在返回一個例外一些點,並再次檢查。我保持這個問題的時間更長一些,以防萬一任何人有更清晰的解決方案(我確信)。

1

我爲這種函數添加一個參數running_times_for_test(默認爲-1),如果running_times達到0,那麼我打破了無限循環。如果running_time等於-1(默認值),照常執行。

+0

聽起來像是另一個有效的方法來解決這個問題:) – maiksensi