2013-01-15 10 views
17

Mam coś takiego w pliku testowego python:Jak naśmiewać się przy użyciu ścieżek względnych ścieżek?

from mock import patch, 
from ..monkey import ook 
[...] 
@patch('monkey.ook', Mock(return_value=None)) 
def test_run_ook (self, mock_ook): 
    self.assertIsNone(ook()) 
    mock_ook.run.assert_called_once_with('') 

Kiedy uruchomić ten test, mam ImportError: No module named monkey. Oczywiście ścieżka, którą łatam, nie jest właściwa. Jednak nie jestem pewien, jak zrobić to dobrze, bez problemów z sys.path lub PYTHONPATH.

Jakieś wskazówki?

Odpowiedz

14

Z czego wnoszę, z udawaną, ty potrzeba dostarczenie przerywana nazwa podczas łatania. Na szczęście każdy moduł ma dostęp do specjalnej zmiennej na poziomie modułu __name__, która zawiera nazwę modułu. Korzystanie z tego, jeśli chcesz załatać zmienne lokalne do modułu, należy móc zrobić coś jak następuje:

import mock 
import unittest 

ook = lambda: "the ook" 


class OokTest(unittest.TestCase): 

    def test_ook(self): 
     with mock.patch(__name__ + '.ook', return_value=None): 
      self.assertIsNone(ook()) 
     self.assertEquals(ook(), "the ook") 

    # the patch decorator should work the same way, I just tend to use the 
    # context manager out of personal preference 
    @mock.patch(__name__ + '.ook', return_value=None) 
    def test_ook_2(self, mock_ook): 
     self.assertIsNone(ook()) 

Zakładając, że już zapisany plik jako quicktest.py, testy jednostkowe dają ten wynik :

$ python -m unittest quicktest 
.. 
---------------------------------------------------------------------- 
Ran 2 tests in 0.001s 

OK 

I oczywiście from a.b import c daje zwykły zmienną c w pakiecie, więc ten sam mechanizm powinien działać.

0

Użyj pełnej ścieżki do importu. Na przykład, jeśli masz ten system plików:

  • root/
    • dumy/
      • foo/
        • module.py
    • dummy2/
      • module2.py

Można importować module.py z module2.py używając:

from root.dummy.foo import module 
+2

-1 jako to nie jest odpowiedź na moje pytanie. Chciałem wiedzieć, jak używać go z ** względnymi ** ścieżkami i ** nie absolutnymi ścieżkami **. – Sardathrion

+0

@Sathathrion Ok, ale nie mówisz nic na ten temat w swoim pytaniu ... Mówisz tylko, że nie chcesz używać sys.path – jvallver

0

Myślę, że to wynika z faktu, że nie importować monkey ale zamiast tego importuj ook. Jeśli importujesz małpy z .., to powinno działać. W przeciwnym razie po prostu wywołaj łatkę na ook.

+0

Kiedy to zrobię, otrzymuję komunikat 'TypeError: Potrzebuję poprawnego celu do poprawienia . Dostarczyłeś: ook' od Mock. – Sardathrion

+0

Następnie zaimportuj 'monkey' zamiast importu' ook', aby oryginalna łatka rzeczywiście działała. –

+0

To nadal nie zadziała, ponieważ 'monkey' nie znajduje się w jednym z katalogów w sys.path. (Właśnie dlatego Sardathrion robi względny import.) W rzeczywistości dekorator łatek nie dba o twój import, ponieważ zaimportuje sam moduł. – balu

1

Nie wiem, czy jest to najlepszy sposób (lub nawet zalecane), ale jeden z nich jest użycie czegoś takiego:

from mock import patch, 
from ..monkey import ook 
[...] 

package_base = __package__.rsplit('.', 1)[0] 

@patch('{0}.monkey.ook'.format(package_base), Mock(return_value=None)) 
def test_run_ook (self, mock_ook): 
    self.assertIsNone(ook()) 
    mock_ook.run.assert_called_once_with('') 
12

użyłem rozwiązanie leo-the-maniakalną na aż natknąłem się na ten jeden użyciem patch.object - która wygląda jeszcze lepiej do mnie:

from unittest.mock import patch, 
from .. import monkey 
[...] 
@patch.object(monkey, 'ook', Mock(return_value=None)) 
def test_run_ook (self, mock_ook): 
    self.assertIsNone(monkey.ook()) 
    mock_ook.run.assert_called_once_with('') 

Zalety:

  • Nie potrzeba kodu boilerplate że to __name__ + '.object_to_be_patched'
  • Wszystkie zależności w przypadku testowym są wyraźnie oznaczone na początku pliku jako instrukcje import.

Wady:

  • nie można zrobić from ..monkey import ook ale trzeba zrobić from .. import monkey oraz dostęp ook przez monkey, tj monkey.ook. W przypadkach, w których muszę to często napisać, dodam do instrukcji importu, dla wygody, numer ook = monkey.ook.
+0

Prawdopodobnie jest kilka wad, ale ** ogólnie jest to bardzo przydatne podejście w wielu przypadkach **! Dziękuję Ci! – maxkoryukov

0

Kiedy robisz from ..monkey import ook z modułu pkg1.pgk2.mymodule co skończyć się to z pkg1.pgk2.mymodule.ook.

To jest teraz ook znajduje się w obszarze nazw modułu, w którym wykonano from ... import .... I to jest cel, który musisz załatać.

Więc po prostu załatać pkg1.pkg2.mymodule.ook:

from unittest.mock import patch # mypackage.mymodule.patch 
from ..monkey import ook  # mypacket.mymodule.ook 

with patch("pkg1.pgk2.mymodule.ook"): 
    .... 

Jak wskazano przez innych, jeśli są łatanie z tego samego modułu, gdzie zrobił importu można użyć __name__ uzyskać przerywaną nazwę pakietu, ale jeśli łatasz z innego modułu, musisz to przeliterować.

Pamiętaj tylko, że cokolwiek importujesz, jest łatane z miejsca docelowego modulethatimports.nameimported.

4

Opierając się na przyjętej odpowiedzi, wierzę, że to jest najczystszym sposobem osiągnięcia zamierzonego celu:

from mock import patch 
from .. import monkey 

@patch(monkey.__name__+'.ook', Mock(return_value=None)) 
def test_run_ook (self, mock_ook): 
    self.assertIsNone(monkey.ook()) 
    mock_ook.run.assert_called_once_with('') 
Powiązane problemy