python - Mock an entire package with pytest and pytest-mock -
i have class uses package tmdbsimple
:
movie.py
import tmdbsimple tmdb tmdb.api_key = '12345' class movie(): def __init__(self, tmdb_id): movie = tmdb.movies(tmdb_id) response = movie.info() self.tmdb_id = tmdb_id self.title = movie.title self.vote_average = movie.vote_average self.watched = false *snip*
this , until want test without relying on actual connection tmdb:
test_movie.py
import pytest import movie fake_tmdbsimple import faketmdbsimple @pytest.fixture def testmovie(mocker): mocker.patch.dict('sys.modules', {'tmdbsimple': faketmdbsimple()}) return movie.movie('1') def test_creation_of_movie(testmovie): assert isinstance(testmovie, movie.movie) def test_properties_of_movie(testmovie): assert testmovie.tmdb_id == 1 assert testmovie.title == 'example movie' assert testmovie.vote_average == 10 assert testmovie.watched == false
fake_tmdbsimple.py
class faketmdbsimple(): def __init__(self): pass class movies(): _example_movie_data = { 1: { 'title': 'example movie', 'vote_average': 10.0 } } def __init__(self, tmdb_id): self.tmdb_id = tmdb_id def info(self): self.title = self._example_movie_data[self.tmdb_id]['title'] self.vote_average = self._example_movie_data[self.tmdb_id]['vote_average'] class find(): def __init__(self, identifier): pass def info(self, external_source): return { 'movie_results': [ {'id': 1} ] } class search(): def __init__(self): pass def movie(self, query): return { 'results': [ { 'id': 1 } ] }
when test runs, error:
*snip* self = <tmdbsimple.movies.movies object @ 0x110779cf8> def __init__(self): > . import api_version e importerror: cannot import name 'api_version'
the test still trying import real tmdbsimple
! testmovie
object still receives instance of tmdbsimple.movies.movies
instead of fake_tmdbsimple.movies
when calling tmdb.movies()
. relatively sure result of "not mocking object used, coming from." however, in case, using pytest
, pytest-mock
, not know how make mock happen needs to.
am going right way? if so, need mock entire tmdbsimple
package? if not, correct way test movie()
class without accessing tmdb?
i had working implementation of before, so:
test_movie.py:
import pytest pycoin import movie @pytest.fixture def testmovie(fake_tmdbsimple): return movie.movie('1') @pytest.fixture def fake_tmdbsimple(monkeypatch): monkeypatch.setattr('tmdbsimple.movies', faketmdbsimplemovies) monkeypatch.setattr('tmdbsimple.find', faketmdbsimplefind) monkeypatch.setattr('tmdbsimple.search', faketmdbsimplesearch) class faketmdbsimplemovies(): _example_movie_data = { 1: { 'title': 'example movie', 'vote_average': 10.0 } } def __init__(self, tmdb_id): self.tmdb_id = tmdb_id def info(self): self.title = self._example_movie_data[self.tmdb_id]['title'] self.vote_average = self._example_movie_data[self.tmdb_id]['vote_average'] class faketmdbsimplefind(): def __init__(self, identifier): pass def info(self, external_source): return { 'movie_results': [ {'id': 1} ] } class faketmdbsimplesearch(): def __init__(self): pass def movie(self, query): return { 'results': [ { 'id': 1 } ] } def test_creation_of_movie(testmovie): assert isinstance(testmovie, movie.movie) def test_properties_of_movie(testmovie): assert testmovie.tmdb_id == 1 assert testmovie.title == 'example movie' assert testmovie.vote_average == 10 assert testmovie.watched == false
this had advantage of not requiring pytest-mock
(and advantage of working...), seemed inelegant patch each of movies
, find
, , search
individually. require re-implementation of fake classes if wanted test other modules fake version of tmdbsimple
. annoys completionist in me tried mock out entire package can't figure out how.
Great Post with valuable information. I am glad that I have visited this site. Share more updates.
ReplyDeletePytest Online Training
Pytest Online Course
Artificial Intelligence Online Course
Nice blog, very informative content.Thanks for sharing, waiting for the next update…
ReplyDeleteWhat is data science?
What are the uses of DataScience?