2013-04-21 20 views
46

Chcę zrozumieć, w jaki sposób uzyskać @patch funkcję z zaimportowanego modułu.Python Wyśmiewanie funkcji z zaimportowanego modułu

To jest, gdzie jestem tak daleko.

APP/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() 

APP/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() 

Działa to tak, jak się spodziewałem. Moduł "załatany" po prostu zwraca niezmienioną wartość get_user_name. Jak wyśmiewać metody z innych pakietów, które importuję do testowanej przestrzeni nazw?

+1

Pytanie dotyczy "kpiny z najlepszych praktyk" lub czy to, co robisz ma sens? Odnośnie pierwszego, chciałbym użyć biblioteki szyderczej, takiej jak ['Mock'] (http://www.voidspace.org.uk/python/mock/), która jest zawarta w python3.3 + jako [' unittest .mock'] (http://docs.python.org/dev/library/unittest.mock). – Bakuriu

+0

Pytam, czy mówię o tym prawie. Spojrzałem na Mock, ale nie widzę sposobu na rozwiązanie tego konkretnego problemu. Czy istnieje sposób na odtworzenie tego, co zrobiłem powyżej w Mock? – nsfyn55

Odpowiedz

66

Kiedy używasz patch dekorator z pakietu unittest.mock jesteś nie łatanie nazw moduł jest importowany z (w tym przypadku app.my_module.get_user_name) Jesteś łatanie go w przestrzeni nazw badanego app.mocking.get_user_name.

Aby wykonać powyższe z Mock spróbować czegoś jak poniżej:

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') 

standardowej dokumentacji biblioteka zawiera użyteczny section opisywaniu tego.

+0

to prowadzi do mojego problemu. 'get_user_name' znajduje się w innym module niż' test_method'. Czy istnieje sposób na wyśmiewanie czegoś w sub_module? Naprawiłem to w brzydki sposób poniżej. – nsfyn55

+4

Nie ma znaczenia, że ​​'get_user_name' znajduje się w innym module niż' test_method', ponieważ importujesz funkcję do 'app.mocking', która znajduje się w tej samej przestrzeni nazw. –

+0

Mam cię. Tak, to działa dzięki! – nsfyn55

5

Podczas gdy odpowiedź Mattiego Johna rozwiązuje twój problem (i pomógł mi również, dziękuję!), Sugerowałbym jednak, aby zastąpić oryginalną funkcję "get_user_name" z wyśmiewaną. Pozwoli to kontrolować, kiedy funkcja zostanie wymieniona, a kiedy nie. Pozwoli to również na dokonanie kilku wymian w tym samym teście. Aby to zrobić, użyj instrukcji "z" w bardzo podobny sposób:

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') 
+0

. Jest to nieistotne dla postawionego pytania. Niezależnie od tego, czy używasz 'łatki 'jako dekoratora czy menedżera kontekstu, jest to specyficzne dla przypadku użycia. Na przykład można użyć 'łatki' jako dekoratora do wyśmiewania wartości dla wszystkich testów w klasie' xunit' lub 'pytest', podczas gdy w innych przypadkach przydatne jest posiadanie precyzyjnej kontroli, którą zapewnia menedżer kontekstu. – nsfyn55