AttributeError: <bound method Manager.get of &l

2019-09-14 03:00发布

问题:

I am not very experimented in unittesting, I am getting the error below and I wasn't able to fix, I would appreciate some help please. Thanks

This is the returned error:

    ======================================================================
ERROR: test_authenticate_credentials_for_inactive_user (apps.authentication.tests.test_authentication.AuthenticateCredentialsTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/site-packages/mock/mock.py", line 1297, in patched
    arg = patching.__enter__()
  File "/usr/local/site-packages/mock/mock.py", line 1369, in __enter__
    original, local = self.get_original()
  File "/usr/local/site-packages/mock/mock.py", line 1343, in get_original
    "%s does not have the attribute %r" % (target, name)
AttributeError: <bound method Manager.get of <django.db.models.manager.Manager object at 0x00000000015bd168>> does not have the attribute 'has_expired'

This is the code:

class ExpiringTokenAuthentication(TokenAuthentication):
    """
    Extends token auth with inactivity expiration mechanism.
    """
    model = ExpiringToken

    def authenticate_credentials(self, key):

        try:
            token = self.model.objects.get(key=key)
        except self.model.DoesNotExist:
            raise exceptions.AuthenticationFailed('Invalid token')

        if not token.user.is_active:
            raise exceptions.AuthenticationFailed('Invalid user')

        if token.has_expired():
            raise exceptions.AuthenticationFailed('Token has expired')

unittest:

class AuthenticateCredentialsTest(TestCase):

    def setUp(self):
        self.ExpiringTokenAuth = ExpiringTokenAuthentication()


    @patch('apps.authentication.authentication.ExpiringTokenAuthentication.model.objects.get')
    @patch('apps.authentication.authentication.ExpiringTokenAuthentication.model.objects.get.user.is_active')
    @patch('apps.authentication.authentication.ExpiringTokenAuthentication.model.objects.get.has_expired')
    def test_authenticate_credentials_for_inactive_user(self, mock_token, active_user, expired_token):
        active_user.return_value = True
        expired_token.return_value = False
        with self.assertRaises(exceptions.AuthenticationFailed) as ea:
            self.ExpiringTokenAuth.authenticate_credentials('valid key')

回答1:

The problem is: you are trying to path a object return by the .get() method, that's not how it works. You need to patch the instance it self:

@patch('apps.authentication.authentication.ExpiringTokenAuthentication.model.objects.get')
@patch('apps.authentication.authentication.token.user.is_active')
@patch('apps.authentication.authentication.token.has_expired')
def test_authenticate_credentials_for_inactive_user(self, mock_token, active_user, expired_token):
    active_user.return_value = True
    expired_token.return_value = False
    with self.assertRaises(exceptions.AuthenticationFailed) as ea:
        self.ExpiringTokenAuth.authenticate_credentials('valid key')


回答2:

You can separate each case in a diferent test. For example:

class AuthenticateCredentialsTest(TestCase):

def setUp(self):
    self.ExpiringTokenAuth = ExpiringTokenAuthentication()
    self.token = ExpiringToken.objects.create(key="valid_key")

def tearDown(self):
    del self.ExpiringTokenAuth
    del self.token

def test_for_non_existent_token(self):
    with self.assertRaises(exceptions.AuthenticationFailed) as ea:
        self.ExpiringTokenAuth.authenticate_credentials('invalid_key')

def test_for_user_inactive(self):
    user = <UserModel>.objects.create(is_active=False, **params)  # Create your own inactive user
    self.token.user = user
    self.token.save()

    with self.assertRaises(exceptions.AuthenticationFailed) as ea:
        self.ExpiringTokenAuth.authenticate_credentials('valid_key')

def test_for_has_expired(self):
    self.token.expired = True  # Make the method has_expired return True
    self.token.save()

    with self.assertRaises(exceptions.AuthenticationFailed) as ea:
        self.ExpiringTokenAuth.authenticate_credentials('valid_key')