扩展/覆盖Django TestCase类

时间:2018-01-30 09:37:38

标签: python django design-patterns django-testing

我的应用程序有三个访问级别(即用户,管理员,管理员)。在我的单元测试中,我有类似的东西:

from django.test import TestCase

class DocumentViewTest(TestCase):
    def setUp(self):
         # Create 3 users

    def test_view_url_exists_at_desired_location(self):
         self.client.login(username='manager', password='xx')
         resp = self.client.get(reverse('view_upload'))
         self.assertEqual(str(resp.context['user']), 'manager')

测试所有三个级别可以由相同的例程定义:

  1. 登录用户
  2. 发布/获取某个网址
  3. 创建断言以检查发布/获取响应
  4. 我想在一些包装类中封装所有步骤或扩展TestCase,以避免冗余。我在考虑这样的事情:

    from django.test import TestCase
    
    class DocumentViewTest(TestCase):
        def setUp(self):
             # Create 3 users
    
        def test_view_url_exists_at_desired_location(self):
             self.client.login(username=['manager','admin','simple_user'], password=['xx','x','xxx'])
             resp_manager, resp_admin, resp_simple_user = self.client.get(reverse('view_upload'))
             self.assertEqual(str(resp_manager.context['user']), 'manager')
             self.assertEqual(str(resp_admin.context['user']), 'admin')
             self.assertEqual(str(resp.resp_simple_user['user']), 'simple_user')
    

    有没有人建议我如何覆盖get / post / login方法?在TestCase周围创建包装类会更容易吗?还有其他建议吗?

    谢谢!

1 个答案:

答案 0 :(得分:0)

这就是我实现上述行为的方式,也许对某人有用:

from django.test.client import Client


class LoginDetails:
    def __init__(self, login_fn, **credentials):
        self._users = [dict(username=name, password=password) for name, password in
                       zip(credentials.get('username'), credentials.get('password'))]
        self._login_fn = login_fn

    def get_login(self):
        for user in self._users:
            yield self._login_fn(**user)


class ClientExtended(Client):
    def login(self, **credentials):
        if isinstance(credentials.get('username'), list):
            return LoginDetails(super(ClientExtended, self).login, **credentials)
        else:
            return super(ClientExtended, self).login(**credentials)

    def get(self, path, *args, **extra):
        if extra.get('login_list'):
            login_list = extra.pop('login_list', None)
            responses = []
            for _ in login_list.get_login():
                responses.append(super(ClientExtended, self).get(path, *args, **extra))
                super(ClientExtended, self).logout()
            return responses
        else:
            return super(ClientExtended, self).get(path, *args, **extra)

    def post(self, path, *args, **extra):
        if extra.get('login_list'):
            login_list = extra.pop('login_list', None)
            responses = []
            for _ in login_list.get_login():
                responses.append(super(ClientExtended, self).post(path, *args, **extra))
                super(ClientExtended, self).logout()
            return responses
        else:
            return super(ClientExtended, self).post(path, *args, **extra)

我的测试现在看起来像这样:

from django.test import TestCase
from xx import ClientExtended


class DocumentViewTest(TestCase):
    def setUp(self):
         self.client = ClientExtended()
         # Create 3 users

    def test_view_url_exists_at_desired_location(self):
         logins = self.client.login(username=['manager','admin','simple_user'], password=['xx','x','xxx'])
         resp_manager, resp_admin, resp_simple_user = self.client.get(reverse('view_upload'), login_list=logins)
         self.assertEqual(str(resp_manager.context['user']), 'manager')
         self.assertEqual(str(resp_admin.context['user']), 'admin')
         self.assertEqual(str(resp.resp_simple_user['user']), 'simple_user')