如何在测试设置中重写一个值

时间:2018-08-27 10:18:57

标签: django django-rest-framework throttling

如何在测试设置中将“用户”:“ 2 /天”改写为“用户”:“ 5 /分钟”

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_RATES': {
         'user': '5/minute'
    }
}

我该如何使用@override_settings或具有上下文管理功能的mb来做到这一点? 我只需要在一个测试中应用它,就不能重写整个字典

def test_mytest(self):
    value = settings.REST_FRAMEWORK
    value['DEFAULT_THROTTLE_RATES'] = {'user':'2/day'}

    data1 = {}
    data2 = {}
    data3 = {}

with self.settings(REST_FRAMEWORK=value):
    resp1 = self.client.post(self.url, data1, format='json')
    resp2 = self.client.post(self.url, data1, format='json')
    resp3 = self.client.post(self.url, data1, format='json')

assert resp3.status_code == 429, resp3.data

尽管值已更改,但没有429错误

3 个答案:

答案 0 :(得分:2)

解决方案1 ​​:使用@override_default()包装器

您要将包装器函数应用于希望使用此值覆盖的viewset

from rest_framework.throttling import UserRateThrottle

class UserViewSet(viewsets.ViewSet):

    @api_view(['PUT'])
    @throttle_classes([UserRateThrottle])
    @override_settings(REST_FRAMEWORK['DEFAULT_THROTTLE_RATES']['user'] = "2/day")
    def update(self, request, pk=None):
        ...

在您希望应用此覆盖的海关值的任何视图或视图集之前添加包装器。

您还希望在settings.py中使用它:

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ),
    'DEFAULT_THROTTLE_RATES': {
        'anon': '100/day',
        'user': '13500/day'
    }
}

解决方案2 :自定义限制类

但是,如果要在测试环境中使用不同的节流率,则可以尝试在settings.py中进行以下操作:

TEST = True ## <-- Set to False when not in testing!!

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.CustomUserRateThrottle'
    )
}

并指定您自己的自定义节流类:

from django.conf import settings

class CustomUserRateThrottle(throttling.UserRateThrottle):
    if settings.TEST:
        THROTTLE_RATES = 'DEFAULT_THROTTLE_RATES': {
            'user': '13500/day',
        }
    else:
        THROTTLE_RATES = 'DEFAULT_THROTTLE_RATES': {
            'user': '2/day',
        } 
    return settings.TEST # <-- Custom throttling classes must always return either True or False, so this makes sense.

解决方案3 :直接在“测试外壳”中:

包括上面定义的自定义包装器,但这一次是在test_something()的{​​{1}}方法中:

test.py

答案 1 :(得分:2)

根据您的用例,您可以采用以下方式之一:

建议1:如果要在少数特定测试案例中覆盖设置,则可以使用@override_settings装饰器。但这对于所有测试用例都没有意义,如果是这样,则可以遵循建议2。

建议2 :这是更通用,更有效的解决方案。

您可以为各种运行环境提供多个设置文件(在设置python模块内部),如下所示:

  1. base.py(包含您的所有基本设置)
  2. local.py(从此处导入*并覆盖/添加特定于本地/开发环境的设置)
  3. test.py(从此处导入*并覆盖/添加特定于测试环境的设置)
  4. 您还可以在prod.py或其他内容中具有特定于生产环境的设置。

使用此设置可以运行类似python manage.py test --settings=yourproject.settings.test的测试

答案 2 :(得分:0)

    from unittest import mock

    @mock.patch('rest_framework.throttling.SimpleRateThrottle.get_rate')
    def test_api(self, get_rate):
        get_rate.return_value = '1/minute'

        from rest_framework.settings import api_settings
        print(api_settings.DEFAULT_THROTTLE_RATES)
        print(api_settings.user_settings)


        url = 'api'

        response = self.client.get(url)
        self.assertEqual(response.status_code, HTTP_200_OK)

        response = self.client.get(url)
        self.assertEqual(response.status_code, HTTP_429_TOO_MANY_REQUESTS)