使用DRF测试Django:为要继承的多个测试用例定义基本测试类的问题

时间:2017-06-18 15:20:06

标签: python django unit-testing

我正在使用Django应用程序,该应用程序在Django REST Framework(DRF)的帮助下公开API。我已经到了需要创建测试框架并且一直在研究DRF和Django测试文档的地步。

我已经定义了一个BaseTestCase类,用于设置所有其他测试用例所需的基本必需数据,以及从ModelTestCase继承的BaseTestCase类,以便按顺序使用所执行的设置。以下是这些看法:

BaseTestCase

class BaseTestCase(APITestCase):
  '''
  This class does basic data setup required to test API endpoints
  Creates 1+ users, sets the client to use that user for auth
  '''

  @classmethod
  def create_data(cls):
    '''
    Create the users needed by automated tests
    '''
    # creates some data used by child test cases            

  @classmethod
  def setUpClass(cls):
    client = APIClient()
    cls.client = client
    # call the method to create necessary base data
    cls.create_data()
    # get a user and set the client to use their auth
    user = get_user_model().objects.get(email='auto-test@test.com')
    client.force_authenticate(user=user)
    # cls.client = client
    super(BaseTestCase, cls).setUpClass()

  def test_base_data(self):
    '''
    This test ensures base data has been created
    '''
    # tests basic data to ensure it's created properly

  def test_get_users(self):
    '''
    This test attempts to get the list of users via the API
    It depends on the class setup being complete and correct
    '''
    url = '/api/users/'
    response = BaseTestCase.client.get(url, format='json')
    print(json.loads(response.content))
    self.assertEqual(response.status_code, status.HTTP_200_OK)

ModelTestCase

class ModelTestCase(BaseTestCase):
  @classmethod
  def setUpClass(cls):
    super(ModelTestCase, cls).setUpClass()
    client = APIClient()
    user = get_user_model().objects.all()[0]
    client.force_authenticate(user=user)
    cls.client = client

  def test_create_model(self):
    '''
    Make sure we can create a new model with the API
    '''
    url = '/api/model/'
    # set the request payload
    response = ModelTestCase.client.post(url, data, format='json')
    self.assertEqual(response.status_code, status.HTTP_201_CREATED)

当我运行所有测试时,我得到一个失败,因为BaseTestCase数据验证断言中的一个(基于存在多少个对象的计数)由于存在太多而失败(因为{{1}已经设置了两次 - 一次是自己的,一次是BaseTestCase setUpClass

的一部分

当我只运行 ModelTestCase时,我收到以下错误:

ModelTestCase

我不明白 - ====================================================================== ERROR: test_get_users (app.tests.ModelTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/path/to/tests.py", line 125, in test_get_users response = BaseTestCase.client.get(url, format='json') AttributeError: type object 'BaseTestCase' has no attribute 'client' ---------------------------------------------------------------------- 的{​​{1}}是否应该正常运行?

我还尝试将setUpClass()定义为继承自BaseTestCase - 使用此配置,运行所有测试成功,但(我相信)仅因为测试按字母顺序运行,因此{ {1}}运行,设置数据,然后ModelTestCase可以使用该数据。

我希望测试本身是独立的 - 我相信APITestCase可以用于此。但是,我还希望客户端设置(用于身份验证)以及数据设置(我认为最终会相对昂贵)在测试用例之间共享,这样就不需要每个案例重复一次这就是为什么我认为创建一个继承的基类是要走的路。

有没有办法完成我所概述的内容?我应该使用BaseTestCase代替ModelTestCase吗?或者有没有办法创建我的setUpData()类并在执行测试时让运行?

1 个答案:

答案 0 :(得分:0)

根据Django Rest Framework Testing部分,您应使用setUp()方法保留默认架构。这就是我找到合理解决方案的方式:

from django.urls import reverse
from rest_framework.test import APITestCase
import pytest

from core.factories import UserFactory, ClientFactory, AdministratorFactory, FacilitatorFactory, ParticipantFactory 


class BaseAPITestCase(APITestCase):
    def setUp(self):
        self.user = UserFactory()
        self.client.force_authenticate(user=self.user)


class UserTestCase(BaseAPITestCase):
    def setUp(self):
        # Call Parent's constructor.
        super(self.__class__, self).setUp()
        self.clients = ClientFactory(user=self.user)
        self.administrator = AdministratorFactory(user=self.user)
        self.facilitator = FacilitatorFactory(user=self.user)
        self.participant = ParticipantFactory(user=self.user)

    def test_get_users(self):
        url = reverse("api_v1:user-list")
        response = self.client.get(url)
        self.assertEquals(response.data["count"], 1)
        self.assertEquals(response.data["results"][0]["username"], self.user.username)
        self.assertEquals(response.status_code, 200)

结果:

============================================================================== test session starts ===============================================================================
platform linux -- Python 3.7.6, pytest-5.3.0, py-1.8.1, pluggy-0.13.1 -- 
cachedir: .pytest_cache
Django settings: tests.settings (from ini file)
Using --randomly-seed=1589794116
plugins: django-3.7.0, django-test-migrations-0.1.0, randomly-3.1.0, hypothesis-4.53.0, timeout-1.3.0, testmon-1.0.0, cov-2.8.0, deadfixtures-2.1.0
collected 1 items                                                                                                                                                               

tests/api/test_basics.py::UserTestCase::test_get_users PASSED