Moduł A
zawiera import B
u góry. Jednak w warunkach testowych chciałbym mock B
w A
(makiety A.B
) i całkowicie powstrzymać się od importu B
.
W rzeczywistości B
nie jest celowo instalowany w środowisku testowym.
A
jest testowaną jednostką. Muszę importować A
z całą jego funkcjonalnością. B
jest modułem, który muszę wyszydzić. Ale jak mogę kpić B
wewnątrz A
i przestać A
importować rzeczywistość B
, jeśli pierwszą rzeczą A
jest importowanie B
?
(Powodem, dla którego B nie jest zainstalowane, jest to, że używam pypy do szybkiego testowania i niestety B nie jest jeszcze kompatybilny z pypy.)
Jak można to zrobić?
źródło
Mock
nie poprawi to niektórych magicznych atrybutów (__%s__
), takich jak__name__
.sys.modules['B'] = None
ale to nie działa.mock
a następnie wywołaćmock.Mock()
Wbudowaną wersję
__import__
można mockować za pomocą biblioteki „mock”, aby uzyskać większą kontrolę:Powiedz
A
wygląda tak:A.a()
zwroty,b_mock.func()
które również można wyszydzić.Uwaga dotycząca Pythona 3: Jak stwierdzono w dzienniku zmian w wersji 3.0 ,
__builtin__
ma teraz nazwębuiltins
:Kod w tej odpowiedzi działa dobrze, jeśli zastąpisz
__builtin__
gobuiltins
dla Pythona 3.źródło
import_mock
wezwany doimport A
, ale nie do niczego, co importuje.ImportError: No module named '__builtin__'
__builtin__
__builtin__
przezbuiltins
dla python3 ( docs.python.org/3/whatsnew/3.0.html?highlight=__builtin__ )Łatwo, po prostu mock bibliotekę w sys.modules, zanim zostanie zaimportowana:
a następnie, o ile
A
nie polega na określonych typach danych zwracanych z obiektów B:powinno po prostu działać.
Możesz też kpić z
import A.B
:Działa to nawet, jeśli masz podmoduły, ale będziesz chciał mockować każdy moduł. Powiedz, że masz to:
Aby wyszydzić, po prostu wykonaj poniższe czynności, zanim zaimportowany zostanie moduł zawierający powyższe:
(Moje doświadczenie: miałem zależność, która działa na jednej platformie, Windows, ale nie działała na Linuksie, gdzie przeprowadzamy nasze codzienne testy. Musiałem więc sfałszować zależność dla naszych testów. Na szczęście była to czarna skrzynka, więc Nie musiałem konfigurować wielu interakcji).
Kpiące efekty uboczne
Dodatek: Właściwie potrzebowałem zasymulować efekt uboczny, który zajął trochę czasu. Więc potrzebowałem metody obiektu, aby zasnąć przez sekundę. To działałoby tak:
A potem kod zajmuje trochę czasu, tak jak prawdziwa metoda.
źródło
Zdaję sobie sprawę, że jestem trochę spóźniony na imprezę tutaj, ale oto nieco szalony sposób na zautomatyzowanie tego za pomocą
mock
biblioteki:(oto przykład użycia)
Powód, dla którego jest to tak absurdalnie skomplikowane, polega na tym, że gdy następuje import, Python w zasadzie to robi (na przykład
from herp.derp import foo
)sys.modules['herp']
istnieje? W przeciwnym razie zaimportuj. Jeśli nadal nieImportError
sys.modules['herp.derp']
istnieje? W przeciwnym razie zaimportuj. Jeśli nadal nieImportError
foo
osys.modules['herp.derp']
. JeszczeImportError
foo = sys.modules['herp.derp'].foo
To zhakowane rozwiązanie ma pewne wady: jeśli coś innego zależy od innych rzeczy w ścieżce modułu, ten rodzaj go zakręca. Działa to również tylko w przypadku rzeczy importowanych w linii, takich jak
lub
źródło
Odpowiedź Aarona Halla mi odpowiada. Chcę tylko wspomnieć o jednej ważnej rzeczy,
jeśli
A.py
to robiszfrom B.C.D import E
wtedy
test.py
musisz kpić z każdego modułu na ścieżce, w przeciwnym razie otrzymaszImportError
źródło
Znalazłem dobry sposób na mockowanie importu w Pythonie. To rozwiązanie Erica Zaadi znalezione tutaj, którego używam po prostu w mojej aplikacji Django .
Mam klasę,
SeatInterface
która jest interfejsem doSeat
klasy modelu. Więc w moimseat_interface
module mam taki import:Chciałem stworzyć izolowane testy dla
SeatInterface
klasy z wyimaginowanąSeat
klasą jakoFakeSeat
. Problem polegał na tym, jak uruchomić testy offline, gdy aplikacja Django nie działa. Miałem poniżej błąd:Rozwiązaniem było:
A potem test magicznie działa OK :)
źródło
Jeśli to zrobisz
import ModuleB
, naprawdę wywołujesz wbudowaną metodę__import__
jako:Możesz nadpisać tę metodę, importując
__builtin__
moduł i tworząc opakowanie wokół__builtin__.__import__
metody. Lub możesz pobawić sięNullImporter
hakiem zimp
modułu. Przechwytywanie wyjątku i Mockowanie modułu / klasy wexcept
Mockowanie -block.Wskaźnik do odpowiednich dokumentów:
docs.python.org:
__import__
Dostęp do wewnętrznych elementów importu za pomocą modułu imp
Mam nadzieję, że to pomoże. Bądź BARDZO doradzony, abyś wkroczył w bardziej tajemnicze granice programowania w Pythonie i że a) dokładne zrozumienie tego, co naprawdę chcesz osiągnąć, oraz b) dokładne zrozumienie konsekwencji jest ważne.
źródło