我有一个使用包 tmdbsimple
的类:
电影.py
import tmdbsimple as 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*
这一切都很好,直到我想在不依赖与 TMDb 的实际连接的情况下对其进行测试:
测试电影.py
import pytest
import movie
from 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
}
]
}
当测试运行时,我得到这个错误:
*snip*
self = <tmdbsimple.movies.Movies object at 0x110779cf8>
def __init__(self):
> from . import API_VERSION
E ImportError: cannot import name 'API_VERSION'
测试仍在尝试从真正的 tmdbsimple
导入! testMovie
对象在调用 tmdb.Movies()
。我比较确定这是我“不 mock 使用对象的地方,而是 mock 它来自哪里”的结果。但是,在这种情况下,使用 pytest
和 pytest-mock
,我不知道如何在需要的地方进行模拟。
我的做法是否正确?如果是这样,我需要做什么才能成功模拟整个 tmdbsimple
包?如果不是,那么在不实际访问 TMDb 的情况下测试我的 Movie()
类的正确方法是什么?
最佳答案
我之前有一个有效的实现,就像这样:
测试电影.py:
import pytest
from 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
这有不需要 pytest-mock
的优点(还有工作的优点......),但是给每个 Movies
打补丁似乎不够优雅,Find
和 Search
分别。如果我想用 tmdbsimple
的假版本测试其他模块,它还需要重新实现假类。这也让我这个完成主义者很恼火,因为我试图模拟整个包,但不知道如何模拟。
关于python - 使用 pytest 和 pytest-mock 模拟整个包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30249659/