Django:如何使用FB权限模拟用户

时间:2017-12-26 19:56:08

标签: python django facebook unit-testing pytest

我需要检查模板的内容是否正确加载。但是,我需要一个拥有Facebook集成的用户。这是我的观点:

def profile(request, user_id):
    """A user's public pledge settings."""
    user = get_object_or_404(SocialUser, pk=user_id)

    # We only want to show profile pages for users with Facebook integration
    try:
        user.social_auth.get(provider='facebook')
    except (UserSocialAuth.DoesNotExist,
            UserSocialAuth.MultipleObjectsReturned):
        raise Http404(_('User does not exist'))

    events = ['A', 'B', 'C']

    context = {
        'APP_ID': settings.SOCIAL_AUTH_FACEBOOK_KEY,
        'user': user,
        'last_event': events[-1],
    }

    return render(request, 'pledges/profile/profile.html', context)

我认为我应该创建一个与UserSocialAuth对象关联的模拟对象,因此我可以跳过该异常。但是,我不知道如何让数据库返回这个模拟对象。

我也在使用pytest进行测试,所以这就是我到目前为止所做的:

import pytest

from unittest import mock
from django.test import Client
from django.urls import reverse
from social_django.models import UserSocialAuth

from pledges.models import SocialUser

TEST_USERNAME = 'testuser'
TEST_PASSWORD = 'password123'
TEST_EMAIL = 'testuser@example.com'

@pytest.fixture()
def create_social_user():
    """Creates a social user"""
    user = mock.Mock(spec=SocialUser)
    return user


@pytest.mark.django_db
def test_everytime_bar_is_displayed_on_profile_page_when_non_logged_in(
        create_social_user):
    user = create_social_user
    # I am not sure how to make this user to be the user gotten from the database
    UserSocialAuth.objects.create(user=user, provider='facebook', uid='1234')
    c = Client()
    response = c.get(reverse('pledges:profile', kwargs={'user_id': user.id}))

    assert b'id="everytime-beta"' in response.content

更新

模板的img元素定义如下:

<img class="img-responsive" alt="fb avatar" src="{{ user.avatar_url }}">

,班级SocialUser如下:

class SocialUser(User):
    class Meta:
        proxy = True

    @property
    def _facebook_graph(self):
        try:
            auth = self.social_auth.get(provider='facebook')
        except (UserSocialAuth.DoesNotExist,
                UserSocialAuth.MultipleObjectsReturned):
            raise AttributeError

        try:
            return GraphAPI(auth.extra_data['access_token'],
                            version=settings.FACEBOOK_API_VERSION)
        except GraphAPIError as e:
            logger.error(e)
            raise AttributeError

    @property
    def avatar_url(self):
        try:
            graph = self._facebook_graph
        except AttributeError as e:
            return ()

        try:
            avatar = graph.get_object('me/picture')
            return avatar['url']
        except (AttributeError,
                GraphAPIError):
            return None

    def friends(self):
        # implementation to get friends from FB API

    @property
    def pledge_settings(self):
        # implementation to get pledge_settings

我得到的错误如下:

Traceback (most recent call last):
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/base.py", line 882, in _resolve_lookup
    current = current[bit]
TypeError: 'SocialUser' object is not subscriptable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
    response = get_response(request)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/user/bairesdev/band_of_coders/chimp/chimp-everytime/pledges/views.py", line 262, in profile
    return render(request, 'pledges/profile/profile.html', context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/shortcuts.py", line 30, in render
    content = loader.render_to_string(template_name, context, request, using=using)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/loader.py", line 68, in render_to_string
    return template.render(context, request)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/backends/django.py", line 66, in render
    return self.template.render(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/base.py", line 207, in render
    return self._render(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/test/utils.py", line 107, in instrumented_test_render
    return self.nodelist.render(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/base.py", line 990, in render
    bit = node.render_annotated(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/base.py", line 957, in render_annotated
    return self.render(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/loader_tags.py", line 177, in render
    return compiled_parent._render(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/test/utils.py", line 107, in instrumented_test_render
    return self.nodelist.render(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/base.py", line 990, in render
    bit = node.render_annotated(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/base.py", line 957, in render_annotated
    return self.render(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/loader_tags.py", line 177, in render
    return compiled_parent._render(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/test/utils.py", line 107, in instrumented_test_render
    return self.nodelist.render(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/base.py", line 990, in render
    bit = node.render_annotated(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/base.py", line 957, in render_annotated
    return self.render(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/loader_tags.py", line 72, in render
    result = block.nodelist.render(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/base.py", line 990, in render
    bit = node.render_annotated(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/base.py", line 957, in render_annotated
    return self.render(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/loader_tags.py", line 72, in render
    result = block.nodelist.render(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/base.py", line 990, in render
    bit = node.render_annotated(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/base.py", line 957, in render_annotated
    return self.render(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/base.py", line 1040, in render
    output = self.filter_expression.resolve(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/base.py", line 708, in resolve
    obj = self.var.resolve(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/base.py", line 849, in resolve
    value = self._resolve_lookup(context)
  File "/Users/user/.local/share/virtualenvs/chimp-everytime/lib/python3.6/site-packages/django/template/base.py", line 890, in _resolve_lookup
    current = getattr(current, bit)
  File "/Users/user/bairesdev/band_of_coders/chimp/chimp-everytime/pledges/models.py", line 48, in avatar_url
    graph = self._facebook_graph
  File "/Users/user/bairesdev/band_of_coders/chimp/chimp-everytime/pledges/models.py", line 39, in _facebook_graph
    return GraphAPI(auth.extra_data['access_token'],
KeyError: 'access_token'

1 个答案:

答案 0 :(得分:0)

我可以使用mock.patch.object解决此问题。基本上我正在做的是使用上下文管理器模拟属性_facebook_graph的返回值:

from unittest import mock

import pytest
from django.test import Client
from django.urls import reverse
from social_django.models import UserSocialAuth

from pledges.models import SocialUser

TEST_USERNAME = 'testuser'
TEST_PASSWORD = 'password123'
TEST_EMAIL = 'testuser@example.com'


@pytest.fixture()
def social_user_with_fb_auth():
    """Creates a social user"""
    user = SocialUser.objects.create_user(username=TEST_USERNAME,
                                          email=TEST_EMAIL,
                                          password=TEST_PASSWORD)
    UserSocialAuth.objects.create(user=user, provider='facebook')

    return user


@pytest.mark.django_db
def test_everytime_bar_is_displayed_on_profile_page_when_non_logged_in(
        social_user_with_fb_auth):
    user = social_user_with_fb_auth
    c = Client()

    with mock.patch.object(SocialUser, '_facebook_graph', return_value=None):
        response = c.get(reverse('pledges:profile',
                                 kwargs={'user_id': user.id}))

    content = response.content.decode()

    assert 'id="everytime-beta"' in content

这就像一个魅力!