Django 测试,模拟 Instagram 响应错误

Django tests, mocking Instagram response error

在过去的几天里,我一直在尝试编写一个简单的测试来检查我的应用程序是否正常工作。我在完成我的程序后立即开始测试,这就是为什么我在之后编写测试。

我正在使用 python-instagram-ext 作为库和 python 版本 3.5.2

实际程序运行正常。它只是从 instagram 中获取数据,将其中一些保存到变量中并打印出来。

def handle_instagram(self, max_tag_id, search_string=settings.SEARCH_STRING, return_count=1):
    instagram_api = InstagramAPI(access_token=access_token, client_secret=client_secret)
    search_string = search_string.replace('#', '')
    recent_media, next_ = instagram_api.tag_recent_media(count=5, max_tag_id=None,tag_name=search_string)

    id = recent_media[0].id
    print(id)

那部分效果很好。但我不希望我的测试从 instagram API 请求数据,所以我使用 mock 来模拟该函数。

from django.test import TestCase
from palautebot.models import Feedback
from django.core.management.base import BaseCommand
from palautebot.management.commands.palautebot import Command
import instagram
import datetime

class TestPalautebotTests(TestCase):
    palautebot_cmd = Command()
@mock.patch('palautebot.management.commands.palautebot.InstagramAPI')
    def test_handle_instagram(self, palautebot_instagram):
        instagram_api = palautebot_instagram.InstagramAPI.return_value
        user = instagram.models.User(1234, full_name='Test Account', username='test', profile_picture='http://pic.jpg')
        recent_media = [instagram.models.Media(
            users_in_photo= [],
            comment_count= 0,
            link= 'https://www.google.fi',
            filter= 'Crema',
            caption= instagram.models.Comment(created_at=datetime.datetime(2017, 6, 12, 9, 5, 10), user=user, id='1234', text='#nofilter Instagram test'),
            like_count= 0,
            id= '0000000000000000001_0000000001',
            comments= [],
            images= {
                'thumbnail': instagram.models.Image('http://www.google.fi', 50, 50),
                'low_resolution': instagram.models.Image('http://www.google.fi', 150, 150),
                'standard_resolution': instagram.models.Image('http://www.google.fi', 400, 400)
            },
            tags= [instagram.models.Tag('nofilter')],
            likes= [],
            user= user,
            type= 'image',
            user_has_liked= False,
            created_time= datetime.datetime(2017, 6, 12, 9, 5, 10))]

        next_ = None
        instagram_response = (recent_media, next_)
        instagram_api.tag_recent_media.return_value = instagram_response
        success_list= self.palautebot_cmd.handle_instagram(None, search_string='#nofilter')
        self.assertEqual(success_list, [True])

我在 facebook api 上有类似的模拟并且工作正常但是当我尝试用 instagram 做这个模拟时它抛出一个错误:

Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/mock/mock.py", line 1305, in patched
    return func(*args, **keywargs)
  File "/home/bew/bew/src/palautebot/palautebot/tests.py", line 80, in test_handle_instagram
    success_list= self.palautebot_cmd.handle_instagram(None, search_string='#helpalaute')
  File "/home/bew/bew/src/palautebot/palautebot/management/commands/palautebot.py", line 162, in handle_instagram
    tag_name=search_string
ValueError: not enough values to unpack (expected 2, got 0)

首先,我确信问题出在我用作 return_value 的数据上。但是,如果我把它取下来,或者尝试用 pickle 将它保存到变量中,这并不重要。在上面的示例中,我使用 instagram 库手动生成数据。数据和我从instagram上得到的数据差不多。

编辑: 原来 python-instagram-ext 库或 instagram api 中发生了一些非常奇怪的事情,因为 max_tag_id 不适用于我的 ID。所以看来问题可能不在于测试,而在于 api.

我无法用之前的方法解决问题,但我找到了解决方法。因此,我没有模拟 instagramAPI,而是通过设置 side_effect 来模拟特定功能。

   class TestPalautebotTests(TestCase):
       def mock_initialize_instagram():
            instagram_api = instagram.client.InstagramAPI(
                access_token='access_token_foo',
                client_secret='client_secret_bar'
            )
            return instagram_api

        def mock_tag_recent_media(count=60, max_tag=None, tag_name=''):
            recent_media_mock = 'instagram-data'
            next_ = None
            mock_data_from_instagram = (recent_media, next_)
            return mock_data_from_instagram

        @mock.patch('palautebot.management.commands.palautebot.Command.initialize_instagram',side_effect=mock_initialize_instagram)
        @mock.patch('palautebot.management.commands.palautebot.InstagramAPI.tag_recent_media',side_effect=mock_tag_recent_media)
        @mock.patch('palautebot.management.commands.palautebot.Command.answer_to_instagram',side_effect=return_true)
        def test_handle_instagram(
            self,
            mock_init_instagram,
            mock_tag_recent_media,
            mock_answer_to_instagram
        ):
            self.assertEqual(self.palautebot_cmd.handle_instagram(None), [True])