Python İçe aktarılan bir modülden bir işlevi alay


125

Nasıl yapılacağını anlamak istiyorum @patchİçe aktarılan bir modülden bir işlevin .

Şimdiye kadar olduğum yer burası.

Uygulamanın / mocking.py:

from app.my_module import get_user_name

def test_method():
  return get_user_name()

if __name__ == "__main__":
  print "Starting Program..."
  test_method()

Uygulamanın / my_module / __ init__.py:

def get_user_name():
  return "Unmocked User"

Test / mock-test.py:

import unittest
from app.mocking import test_method 

def mock_get_user():
  return "Mocked This Silly"

@patch('app.my_module.get_user_name')
class MockingTestTestCase(unittest.TestCase):

  def test_mock_stubs(self, mock_method):
    mock_method.return_value = 'Mocked This Silly')
    ret = test_method()
    self.assertEqual(ret, 'Mocked This Silly')

if __name__ == '__main__':
  unittest.main()

Bu mu değil ben beklediğiniz gibi çalışır. "Yamalı" modül basitçe unmocked değerini döndürür get_user_name. Test edilen bir ad alanına aktardığım diğer paketlerden yöntemlerle nasıl alay edebilirim?


1
Soru, "en iyi uygulamalarla dalga geçme" ile ilgili veya yaptığınız şeyin mantıklı olup olmadığı? İlki ile ilgili olarak Mock, python3.3 + as gibi bir alay kitaplığı kullanmayı söyleyebilirim unittest.mock.
Bakuriu

Bunu doğru yapıp yapmadığımı soruyorum. Mock'a baktım, ancak bu sorunu çözmenin bir yolunu göremiyorum. Mock'ta yukarıda yaptığım şeyi yeniden yaratmanın bir yolu var mı?
nsfyn55

Yanıtlar:


167

Kullandığınız zaman patchgelen dekoratör unittest.mocksen edilir pakete değil (bu durumda modül ithal edilmektedir ad yama app.my_module.get_user_nametest edilen ad bunu yama edilir)app.mocking.get_user_name .

Yukarıdakileri yapmak Mockiçin aşağıdakine benzer bir şey deneyin:

from mock import patch
from app.mocking import test_method 

class MockingTestTestCase(unittest.TestCase):

    @patch('app.mocking.get_user_name')
    def test_mock_stubs(self, test_patch):
        test_patch.return_value = 'Mocked This Silly'
        ret = test_method()
        self.assertEqual(ret, 'Mocked This Silly')

Standart kitaplık belgeleri, bunu açıklayan yararlı bir bölüm içerir .


bu benim sorunuma geliyor. get_user_nameöğesinden farklı bir modülde test_method. Alt_modüldeki bir şeyle dalga geçmenin bir yolu var mı? Aşağıda çirkin bir şekilde düzelttim.
nsfyn55

6
get_user_nameFarklı bir modülde test_methodolması, işlevi app.mockingaynı ad alanında oldukları için içe aktardığınızdan beri fark etmez .
Matti John

2
Test_patch nereden geldi, tam olarak nedir?
Mike G

2
test_patch, yama dekoratörü tarafından aktarılır ve alay edilen get_user_name nesnesidir (yani MagicMock sınıfının bir örneği). Böyle bir isimle adlandırılsaydı daha net olabilirdi get_user_name_patch.
Matti John

Test_method'a nasıl atıfta bulunuyorsunuz? Hata, NameError: genel adı 'test_method' tanımlanmadı
Aditya

12

Matti John'un cevabı sorununuzu çözerken (ve bana da yardımcı oldu, teşekkürler!), Bununla birlikte, orijinal 'get_user_name' işlevinin sahte olanla değiştirilmesini öneririm. Bu, işlevin ne zaman değiştirilip değiştirilmeyeceğini kontrol etmenizi sağlar. Ayrıca bu, aynı testte birkaç değişiklik yapmanıza da olanak tanır. Bunu yapmak için, 'with' ifadesini oldukça benzer bir şekilde kullanın:

from mock import patch

class MockingTestTestCase(unittest.TestCase):

    def test_mock_stubs(self):
        with patch('app.mocking.get_user_name', return_value = 'Mocked This Silly'):
            ret = test_method()
            self.assertEqual(ret, 'Mocked This Silly')

6
Bu, sorulan soru için önemsizdir. Kullanmak İster patchbir dekoratör veya bağlam yöneticisi olarak kullanılması durumunda özgüdür. Örneğin patch, bir xunitveya pytestsınıftaki tüm testler için bir değerle alay etmek için bir dekoratör olarak kullanabilirsiniz , diğer durumlarda ise bağlam yöneticisi tarafından sağlanan ince taneli kontrole sahip olmak yararlıdır.
nsfyn55
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.