2015-02-24 23 views
10

Python'da (2.7) foo yapan ve foo çalışmazsa 5 dakika sonra pes edecek bir yöntemim var.python işlev yerel değişkenini geçersiz kılmayı geçersiz kılma

def keep_trying(self): 
    timeout = 300 #empirically derived, appropriate timeout 
    end_time = time.time() + timeout 
    while (time.time() < end_time): 
     result = self.foo() 
     if (result == 'success'): 
      break 
     time.sleep(2) 
    else: 
     raise MyException('useful msg here') 

foo() 'dan bazı olası sonuçları biliyorum, bu yüzden bu dönüş değerlerini sahte yapmak için sahte kullanıyorum. Sorun şu ki, testin istisnayı görmeden önce 5 dakika çalışmasını istemiyorum.

Bu yerel zaman aşımı değerini geçersiz kılmanın bir yolu var mı? Sadece birkaç saniye olmasını istiyorum, böylece döngüyü birkaç kez denedim, sonra pes et ve yükselt.

şu çalışmaz:

@patch.object(myClass.keep_trying, 'timeout') 
@patch.object(myClass, 'foo') 
def test_keep_trying(self, mock_foo, mock_timeout): 
    mock_foo.return_value = 'failed' 
    mock_timeout.return_value = 10 # raises AttributeError 
    mock_timeout = 10 # raises AttributeError 
    ... 

cevap

11

Aksine timeout, sen time.time() dönüş değeri alay isteyeceksiniz eğer değerini alay çalışırken daha.

örn. Şimdi ilk kez time.time() denir

@patch.object(time, 'time') 
def test_keep_trying(self, mock_time): 
    mock_time.side_effect = iter([100, 200, 300, 400, 500, 600, 700, 800]) 
    ... 

, 100'le değerini elde edersiniz, bu yüzden ne zaman while döngüsünün birkaç dönüşler sonra zaman aşımı olmalıdır. Ayrıca, time.sleep ile alay edebilirsiniz ve kodun bir bölümünün düzgün çalıştığından emin olmak için kaç kez çağrıldığını belirleyebilirsiniz.

def keep_trying(self, timeout=300): 
    ... 

Bu ne zaman aşımını belirlemenizi sağlar: (yukarıda birine tamamen dik değildir)


diğer yaklaşım kullanıcı işlevine opsiyonel zaman aşımı anahtar sözcüğü geçmesine izin vermektir testlerde (ve 5 dakika beklemek istemeyen gelecekteki kodlarda) ;-).

+0

mock_time öyle! – anregen

+0

Aslında, bu modüle ait mock.side_effect öğesini yerel olarak tutmak için '@ patch.object (myClass.time, 'time')' işlevini kullandım. – anregen

11

Bir işlevin yerel değişkeniyle dalga geçemezsiniz. test etmek daha kolay kodunuzu yapmak için, örneğin olarak değiştirin:

def keep_trying(self, timeout=300): 
    end_time = time.time() + timeout 
    # etc, as above 

yüzden testler daha kısa zaman aşımı ile çalıştırmak için önemsiz hale gelir!

+0

Ve ben de bunu benim cevabım içine düzenliyordum ... :-) – mgilson

+3

Orijinal işlev yayınlanmış bir API'nin bir parçası, bu yüzden imzayı değiştirmek istemiyorum ve kullanıcıların erişim sahibi olmasını istemiyorum. zaman aşımını ayarla. – anregen

+3

Python, bir centilmenlik anlaşması ve bazı sözleşmeler olarak çalışır - argümanın tek başına bir altçizgisine sahip olmanız durumunda - kullanıcılarınız, argümanın kullanılmaması gerektiğini bileceklerdir - ve herhangi bir iyi dokümantasyon sistemi, özel argümanları, yöntemleri, alanları çıkarmanıza izin verecektir. Her neyse, bu yüzden sadece çok kararlı bir kullanıcı ilk sırada argümanı bulacaktır. –