【问题标题】:Testing Django w/ DRF: issues defining a base test class for multiple test cases to inherit使用 DRF 测试 Django:定义要继承的多个测试用例的基测试类的问题
【发布时间】:2017-06-18 15:20:06
【问题描述】:

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

我定义了一个BaseTestCase 类,它设置所有其他测试用例所需的基本必需数据,以及一个继承自BaseTestCaseModelTestCase 类,以便利用执行的设置。这些是现在的样子:

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 数据验证断言之一(基于存在的对象的计数)由于太多(因为 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'

----------------------------------------------------------------------

我不明白 - setUpClass()BaseTestCase 不应该正常运行吗?

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

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

有没有办法完成我概述的内容?我应该使用setUpData() 而不是setUpClass() 吗?或者有没有办法创建我的BaseTestCase 类并在执行测试时运行它?

【问题讨论】:

    标签: python django unit-testing


    【解决方案1】:

    根据 Django Rest Framework 测试部分,您应该使用 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多