Skip to main content
 首页 » 编程设计

python之如何模拟在 __init__ 中实例化的类属性

2025年05月04日34over140

我正在尝试模拟 VKAuth 类中的“self.api.friends.get”方法:

import vk 
 
class VKAuth(object): 
    def __init__(self, access_token, user): 
        self.session = vk.Session(access_token = access_token) 
        self.api = vk.API(self.session) 
 
    def follow(self): 
        vk_friends = self.api.friends.get() 

来自测试模块 test_views.py:

from mock import patch 
from ..auth_backends.vk_backend import VKAuth 
 
class AddUsersToList(TestCase): 
    def test_auth_vk(self, mock_get): 
         ... etc ... 
        auth_token = 'ceeecdfe0eb4bf68ceeecdfe0eb4bf68ceeecdfe0eb4bf68652530774ced6cbc8cba0' 
        token = user.auth_token.key 
        self.client.defaults['HTTP_AUTHORIZATION'] = 'Token {}'.format(token) 
        with patch.object(accounts.auth_backends.vk_backend.VKAuth, 'api'): #point where we're mocking 
            response = self.client.post(reverse('auth-social', kwargs=dict(backend='vk')), dict(access_token=auth_token), follow=True) 

在基于 SNView 类的 View 中调用上面的“auth-social”期间创建了 VKAuth 类的实例:

class SNView(generics.GenericAPIView): 
    serializer_class = serializers.AuthSocialSerializer 
    permission_classes = (rest_permissions.IsAuthenticated) 
 
    def post(self, request, backend, *args, **kwargs): 
        s = self.get_serializer(data=request.DATA) 
 
        if s.is_valid(): 
            auth_backends = { 
                'vk': VKAuth, 
                'facebook': FBAuth 
            } 
 
            if backend in auth_backends: 
                auth_backend = auth_backends[backend](access_token=s.data['access_token'], user=self.request.user) 

我得到一个错误:

AttributeError: <class 'accounts.auth_backends.vk_backend.VKAuth' doens't have the attribute 'api' 

我应该写什么来代替当前的 patch.object 来访问 api.friends.get 并模拟它?

更新:

更准确地说,我想要一些等价物:

    auth_token = 'ceeecdfe0eb4bf68ceeecdfe0eb4bf68ceeecdfe0eb4bf68652530774ced6cbc8cba0' 
    user = User.objects.get(id = 2) 
    vk_auth = VKAuth(auth_token, user) 
 
    vk_ids=[111111,2222222,3333333,44444444] 
    vk_auth.authenticate() 
    vk_auth.api.friends = MagicMock(name='get', return_value=None) 
    vk_auth.api.friends.get = MagicMock(name='get', return_value=vk_ids) 
    data = vk_auth.follow() 

但在我们通过 self.client.post() 向 django-rest-framework api 发出请求之前模拟它。

谢谢!

请您参考如下方法:

你打错了补丁。在 VKAuth 中:

self.api = vk.API(self.session) 

将 api 属性添加到 VKAuth self object。当你打电话时

patch.object(accounts.auth_backends.vk_backend.VKAuth, 'api') 

您正在修补 VKAuth 类的 api 静态属性,而不是对象属性。

您应该改为修补 vk.API。

with patch('vk.API', autospec=True) as mock_api: 
    response = self.client.post(reverse('auth-social', kwargs=dict(backend='vk')), dict(access_token=auth_token), follow=True) 

注释:

  1. 使用patch.object仅当您真正知道为什么需要它而不是简单的补丁时。
  2. autospec=True 不是强制性的,但 I strongly encourage to use it .
  3. 在 patch 上下文中 self.api 将等于 mock_api.return_value 因为调用 vk.API(self.session ) 就像调用 mock_api();换句话说,mock_api 是用于替换 vk.API 引用的模拟对象。
  4. 查看where to patch ,您会发现它非常有用。

现在,如果你想通过一些行为填充你的mock_api.return_value,你可以在with上下文中配置它:

with patch('vk.API', autospec=True) as mock_api: 
    m_api = mock_api.return_value 
    m_api.friends.return_value = None 
    m_api.friends.get.return_value = vk_ids 
    .... Your test