Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在django中测试django rq(python rq)的最佳实践_Python_Django_Testing_Python Rq - Fatal编程技术网

在django中测试django rq(python rq)的最佳实践

在django中测试django rq(python rq)的最佳实践,python,django,testing,python-rq,Python,Django,Testing,Python Rq,我将开始在我的项目中使用django rq Django与RQ的集成,RQ是一个基于Redis的Python队列库 测试使用RQ的django应用程序的最佳实践是什么 例如,若我想将我的应用程序作为黑盒进行测试,那个么在用户执行某些操作后,我想执行当前队列中的所有作业,然后检查我数据库中的所有结果。如何在django测试中执行此操作?当队列中仍有作业时,您需要暂停测试。要执行此操作,您可以检查队列。是否为空(),如果队列中仍有作业,则暂停执行: import time from django.u

我将开始在我的项目中使用django rq

Django与RQ的集成,RQ是一个基于Redis的Python队列库

测试使用RQ的django应用程序的最佳实践是什么


例如,若我想将我的应用程序作为黑盒进行测试,那个么在用户执行某些操作后,我想执行当前队列中的所有作业,然后检查我数据库中的所有结果。如何在django测试中执行此操作?

当队列中仍有作业时,您需要暂停测试。要执行此操作,您可以检查队列。是否为空(),如果队列中仍有作业,则暂停执行:

import time
from django.utils.unittest import TestCase
import django_rq

class TestQueue(TestCase):

def test_something(self):
    # simulate some User actions which will queue up some tasks

    # Wait for the queued tasks to run
    queue = django_rq.get_queue('default')
    while not queue.is_empty():
        time.sleep(5) # adjust this depending on how long your tasks take to execute

    # queued tasks are done, check state of the DB
    self.assert(.....)
我刚刚发现,它允许您在测试环境中启动一个worker,该环境执行队列中的任何任务,然后退出

from django.test impor TestCase
from django_rq import get_worker

class MyTest(TestCase):
    def test_something_that_creates_jobs(self):
        ...                      # Stuff that init jobs.
        get_worker().work(burst=True)  # Processes all jobs then stop.
        ...                      # Asserts that the job stuff is done.

我把我的
rq
测试分成了几个部分

  • 测试我是否正确地将内容添加到队列(使用模拟)
  • 假设如果有东西被添加到队列中,它最终将被处理。(
    rq
    的测试套件应该包括这一点)
  • 测试,如果输入正确,我的任务按预期工作。(正常代码测试)
  • 正在测试的代码:

    def handle(self, *args, **options):
        uid = options.get('user_id')
    
        # @@@ Need to exclude out users who have gotten an email within $window
        # days.
        if uid is None:
            uids = User.objects.filter(is_active=True, userprofile__waitlisted=False).values_list('id', flat=True)
        else:
            uids = [uid]
    
        q = rq.Queue(connection=redis.Redis())
    
        for user_id in uids:
            q.enqueue(mail_user, user_id)
    
    我的测试:

    class DjangoMailUsersTest(DjangoTestCase):
        def setUp(self):
            self.cmd = MailUserCommand()
    
        @patch('redis.Redis')
        @patch('rq.Queue')
        def test_no_userid_queues_all_userids(self, queue, _):
            u1 = UserF.create(userprofile__waitlisted=False)
            u2 = UserF.create(userprofile__waitlisted=False)
            self.cmd.handle()
            self.assertItemsEqual(queue.return_value.enqueue.mock_calls,
                                  [call(ANY, u1.pk), call(ANY, u2.pk)])
    
        @patch('redis.Redis')
        @patch('rq.Queue')
        def test_waitlisted_people_excluded(self, queue, _):
            u1 = UserF.create(userprofile__waitlisted=False)
            UserF.create(userprofile__waitlisted=True)
            self.cmd.handle()
            self.assertItemsEqual(queue.return_value.enqueue.mock_calls, [call(ANY, u1.pk)])
    
    我承诺让你做到:

    from django.test impor TestCase
    from django_rq import get_queue
    
    class MyTest(TestCase):
        def test_something_that_creates_jobs(self):
            queue = get_queue(async=False)
            queue.enqueue(func) # func will be executed right away
            # Test for job completion
    

    这将使测试RQ作业更容易。希望有帮助

    以防万一这对任何人都有帮助。我使用了一个带有自定义模拟对象的补丁来执行立即运行的排队

    #patch django_rq.get_queue
    with patch('django_rq.get_queue', return_value=MockBulkJobGetQueue()) as mock_django_rq_get_queue:
        #Perform web operation that starts job. In my case a post to a url
    
    然后模拟对象只有一个方法:

    class MockBulkJobGetQueue(object):
    
        def enqueue(self, f, *args, **kwargs):
            # Call the function
            f(
                **kwargs.pop('kwargs', None)
            )
    

    我在本例中所做的是检测我是否正在测试,并在测试期间使用fakeredis。最后,在测试本身中,我以同步模式将redis worker任务排队:

    首先,定义一个函数,用于检测您是否正在测试:

    TESTING = len(sys.argv) > 1 and sys.argv[1] == 'test'
    
    def am_testing():
        return TESTING
    
    然后在使用redis对任务进行排队的文件中,以这种方式管理队列。 如果需要,可以扩展get_队列以指定队列名称:

    if am_testing():
        from fakeredis import FakeStrictRedis 
        from rq import Queue
        def get_queue():
            return Queue(connection=FakeStrictRedis())
    
    else:
        import django_rq
        def get_queue():
            return django_rq.get_queue()
    
    然后,将任务按如下方式排队:

    queue = get_queue()
    queue.enqueue(task_mytask, arg1, arg2)
    
    最后,在您的测试程序中,以同步模式运行您正在测试的任务,以便它与您的测试在同一进程中运行。作为实践,我首先清除fakeredis队列,但我认为没有必要,因为没有工人:

    from rq import Queue
    from fakeredis import FakeStrictRedis
    
    FakeStrictRedis().flushall()
    queue = Queue(async=False, connection=FakeStrictRedis())
    queue.enqueue(task_mytask, arg1, arg2)
    
    my settings.py具有正常的django_redis设置,因此django_rq.getqueue()在部署时使用这些设置:

    RQ_QUEUES = {
        'default': {
            'HOST': env_var('REDIS_HOST'),
            'PORT': 6379,
            'DB': 0,
            # 'PASSWORD': 'some-password',
            'DEFAULT_TIMEOUT': 360,
        },
        'high': {
            'HOST': env_var('REDIS_HOST'),
            'PORT': 6379,
            'DB': 0,
            'DEFAULT_TIMEOUT': 500,
        },
        'low': {
            'HOST': env_var('REDIS_HOST'),
            'PORT': 6379,
            'DB': 0,
        }
    }
    

    我遇到了同样的问题。此外,我在工作中执行了一些邮件功能,然后想检查Django测试邮箱是否有任何电子邮件。但是,由于使用Django RQ的作业不会在与Django测试相同的上下文中执行,因此发送的电子邮件不会在测试邮箱中结束

    因此,我需要在相同的上下文中执行作业。这可以通过以下方式实现:

    from django_rq import get_queue
    queue = get_queue('default')
    queue.enqueue(some_job_callable)
    
    # execute input watcher
    jobs = queue.get_jobs()
    
    # execute in the same context as test
    while jobs:
        for job in jobs:
            queue.remove(job)
            job.perform()
        jobs = queue.get_jobs()
    
    # check no jobs left in queue
    assert not jobs
    

    在这里,您只需从队列中获取所有作业,并在测试中直接执行它们。可以在TestCase类中很好地实现这一点,并重用这一功能。

    是否可以将任意队列更改为单独的测试队列?是否可以从
    /manage.py test
    运行redis和worker?实际上,另一个问题是让队列使用测试数据库。首先看一下命名测试数据库。我不建议在manage.py测试中运行Redis,这是不必要的额外复杂性。您可能会发现这一点很有用:投票选择正确的方法——不确定代码。对整个Redis堆栈进行测试是个坏主意。修补
    rq.Queue
    对我来说不起作用。我看不到任何来电。我必须修补
    myapp.my_module.django_rq
    。有一个咒语:“模仿一件物品在哪里使用,而不是它来自哪里。”下面是一些很好的答案——为什么不接受一个呢?祝你好运当前的答案都没有说明如何确保Redis实例被模拟或与真实实例分离(Django隔离测试数据库的方式)。为什么不像芹菜那样使用全局设置?这仍然使用真实的Redis实例来收集作业,而不是模拟Redis实例或命名空间实例。