首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用pytest和pytest-mock模拟整个包

使用pytest和pytest-mock模拟整个包
EN

Stack Overflow用户
提问于 2015-05-15 08:30:58
回答 1查看 4.9K关注 0票数 4

我有一个使用包tmdbsimple的类

movie.py

代码语言:javascript
复制
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的实际连接:

test_movie.py

代码语言:javascript
复制
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

代码语言:javascript
复制
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
                    }
                ]
            }

当测试运行时,我得到这个错误:

代码语言:javascript
复制
*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()时仍然接收tmdbsimple.movies.Movies的实例,而不是fake_tmdbsimple.Movies的实例。我相对确定这是我“不嘲笑对象的使用位置,而是它来自哪里”的结果。然而,在这种情况下,使用pytestpytest-mock,我不知道如何让模拟在需要的地方发生。

我这样做对吗?如果是这样,我需要做什么才能成功模拟整个tmdbsimple包?如果不是,那么在不实际访问TMDb的情况下测试Movie()类的正确方法是什么?

EN

回答 1

Stack Overflow用户

发布于 2015-05-15 08:51:37

我以前有一个可以工作的实现,如下所示:

test_movie.py:

代码语言:javascript
复制
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的优点(也有工作的优点……),但是单独给MoviesFindSearch打补丁似乎并不优雅。如果我想用一个假的tmdbsimple版本测试其他模块,还需要重新实现假的类。这也让我内心的完成主义者感到恼火,因为我试图模拟出整个包,但却找不到方法。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30249659

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档