Python sahte çoklu dönüş değerleri


169

Pythons mock.patch kullanıyorum ve her çağrı için dönüş değerini değiştirmek istiyorum. İşte uyarı: yamalanan fonksiyonun hiçbir girişi yoktur, bu yüzden girişe göre dönüş değerini değiştiremiyorum.

İşte referans için kodum.

def get_boolean_response():
    response = io.prompt('y/n').lower()
    while response not in ('y', 'n', 'yes', 'no'):
        io.echo('Not a valid input. Try again'])
        response = io.prompt('y/n').lower()

    return response in ('y', 'yes')

Test kodum:

@mock.patch('io')
def test_get_boolean_response(self, mock_io):
    #setup
    mock_io.prompt.return_value = ['x','y']
    result = operations.get_boolean_response()

    #test
    self.assertTrue(result)
    self.assertEqual(mock_io.prompt.call_count, 2)

io.prompt"input" un platformdan bağımsız (python 2 ve 3) versiyonudur. Nihayetinde ben kullanıcıların giriş alay etmeye çalışıyorum. Dönüş değeri için bir liste kullanarak denedim, ama bu işe yaramaz.

Dönüş değeri geçersizse, burada sonsuz bir döngü alacağımı görebilirsiniz. Bu yüzden sonunda testimin bitmesi için dönüş değerini değiştirmenin bir yoluna ihtiyacım var.

(bu soruyu cevaplamanın bir başka olası yolu, bir birim testindeki kullanıcı girişini nasıl taklit edebileceğimi açıklamak olabilir)


Bu sorunun bir kopyası değil değil, çünkü girişleri değiştirme yeteneğim yok.

Bu soruya verilen cevabın yorumlarından biri aynı çizgidedir, ancak cevap / yorum yapılmamıştır.


3
response is not 'y' or 'n' or 'yes' or 'no'içinde değil sen öyle bildiğini yapmak. Bkz. Bir değişkeni birden çok değere karşı nasıl test ederim? ve gerektiği değil kullanmak isdize değerleri, kullanımını karşılaştırmak için ==karşılaştırma değerleri değil, nesne kimlikleri.
Martijn Pieters

Burada da dikkatli ol. isDize değişmezlerini karşılaştırmak için kullanmaya çalıştığınız anlaşılıyor . Bunu yapma. Çalışması (bazen) sadece CPython'da bir uygulama detayıdır. Ayrıca, response is not 'y' or 'n' or 'yes' or 'no'muhtemelen düşündüğünüzü yapmıyor ...
mgilson

Yanıtlar:


301

Bir yinelenebilir olarak atayabilirsiniz side_effectve sahte, her çağrıldığında sıradaki bir sonraki değeri döndürür:

>>> from unittest.mock import Mock
>>> m = Mock()
>>> m.side_effect = ['foo', 'bar', 'baz']
>>> m()
'foo'
>>> m()
'bar'
>>> m()
'baz'

Mock()Belgelerin alıntılanması :

Eğer side_effect bir iterable o zaman taklidinin her çağrı iterable sonraki değeri döndürecektir.

Bir kenara, deney response is not 'y' or 'n' or 'yes' or 'no'olacak değil çalışmak; ifadenin (response is not 'y')doğru olup olmadığını mı soruyorsunuz 'y'(her zaman böyle, boş olmayan bir dize her zaman doğrudur), vb. orİşletmenlerin her iki tarafındaki çeşitli ifadeler bağımsızdır . Bkz. Bir değişkeni birden çok değere karşı nasıl test ederim?

Sen gerektiğini de kullanmayan isbir dize karşı test edilecek. CPython yorumlayıcısı , belirli koşullar altında dize nesnelerini yeniden kullanabilir , ancak bu, güvenmeniz gereken davranış değildir.

Bu nedenle, şunları kullanın:

response not in ('y', 'n', 'yes', 'no')

yerine; bu , aynı içeriğe (değere) sahip bir dizeye başvuru yapıp yapmadığını belirlemek için eşitlik testleri ( ==) kullanır response.

Aynısı response == 'y' or 'yes'; kullanın response in ('y', 'yes').


Bunu standartla yapmanın bir yolu var mı mock? Standart sahte ile yaptığım gibi MagicMock ile yama kullanmanın bir yolu var mı?
Nick Humrich

@Humdinger: Bu, Mockstandart sınıfın bir özelliğidir .
Martijn Pieters

17
Bir liste atamak sadece python 3 ile çalışıyor gibi görünüyor. Python 2.7 ile test etme Bunun yerine bir yineleyici kullanmam gerekiyor ( m.side_effect = iter(['foo', 'bar', 'baz'])).
user686249

1
@ user686249: Bir yöntemden belirtmek bir lambda(işlev) değil, bir ürettiği için bunu gerçekten yeniden üretebilirim MagicMock. Bir fonksiyon nesnesi olamaz sahip , yani özelliklere side_effectöznitelik vardır bir iterable olması. Yine de böyle bir yöntem belirtmemelisiniz. Daha iyi kullanım mock.patch.object(requests.Session, 'post'); bu, yöntemin düzgün şekilde otomatik olarak belirtildiği veside_effect düzgün şekilde desteklendiği bir yamalı nesneye neden olur .
Martijn Pieters

3
@ JoeMjr2: Yineleyici bittiğinde StopIterationyükseltilir. Herhangi bir yineleyici kullanabilirsiniz, böylece bir kez itertools.chain(['Foo'], itertools.repeat('Bar'))üretmek için kullanabilirsiniz Foo, sonra sonsuza kadar üretebilirsiniz Bar.
Martijn Pieters
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.