Django DRF 单元测试通过未执行的元类添加了动态混合
Django DRF unit tests added with dynamic mixins via metaclass not being executed
我正在尝试测试 DRF 端点,并尝试将混合动态添加到测试中,以便再次执行测试端点中允许的每种方法(get、post、put、patch、delete)
所以,我的想法是做一个基础测试 class,如果允许的话,它会自动添加一些混合到测试端点。我可以创建将从该基础继承的实际测试 class。
代码:
from rest_framework.test import APITestCase
class GetTestMixin:
def test_get_all(self):
response = self.client.get(self.uri)
self.assertEqual(response.status_code,status.HTTP_200_OK)
class AutoMixinMeta(type):
def __call__(cls, *args, **kwargs):
allowed_methods = ['get', 'post']
# cls would be the Test class, for example TestExample
# cls.__bases__ is a tuple with the classes inherited in the Test class, for example:
# (<class 'unit_tests.endpoints.base_test.RESTTestCase'>, <class 'rest_framework.test.APITestCase'>)
bases = cls.__bases__
for method in allowed_methods:
bases += (cls.method_mixins[method.lower()],)
# Create a new instance with all the mixins
cls = type(cls.__name__, bases, dict(cls.__dict__))
return type.__call__(cls, *args, **kwargs)
class RESTTestCase(metaclass=AutoMixinMeta):
uri = None
method_mixins = {
'post': PostTestMixin,
'get': GetTestMixin,
}
class TestExample(RESTTestCase, APITestCase):
uri = reverse('somemodel-list')
我期待 test_get_all 被执行,但它没有被执行。
混合到位。我在 TestExample
中创建了一个虚拟方法并放置了一个调试器,然后检查它,如下所示:
(Pdb) self.__class__
<class 'TestExample'>
(Pdb) self.__class__.__bases__
(<class 'RESTTestCase'>, <class 'rest_framework.test.APITestCase'>, <class 'GetTestMixin'>)
问题是收集要测试的 classes 的代码永远不会“看到”class 作为测试 classes 的一个实例,或者作为a subclass of: 从测试用例继承的 class 只有在创建实例时才存在。
实现此功能的唯一方法是在导入时创建派生的 classes,并将所需的动态 classes 绑定为模块上的顶级名称。
为此,您可以取消元class,只需将语句放在模块主体中,将新的 class 或 classes 分配给名称使用globals()
。或者,如果您只需要 subclasses,而不是模块顶层,则可以将代码放在 __init_subclass__
方法中。此方法在创建 class 时调用,而不是在实例化时调用,它应该可以工作。
from rest_framework.test import APITestCase
class GetTestMixin:
def test_get_all(self):
response = self.client.get(self.uri)
self.assertEqual(response.status_code,status.HTTP_200_OK)
class RESTTestCase():
uri = None
method_mixins = {
'post': PostTestMixin,
'get': GetTestMixin,
}
def __init_subclass__(cls, *args, **kw):
super.__init_subclass__(*args, **kw)
if "Dynamic" in cls.__name__:
return
allowed_methods = ['get', 'post']
bases = list(cls.__bases__)
for method in allowed_methods:
bases.append(cls.method_mixins[method.lower()])
# Create a new instance with all the mixins
new_cls = type(cls.__name__ + "Dynamic", bases, dict(cls.__dict__))
globals()[new_cls.__name__] = new_cls
class TestExample(RESTTestCase, APITestCase):
uri = reverse('somemodel-list')
# class TestExampleDynamic is created automatically when the `class` statement above resolves
我正在尝试测试 DRF 端点,并尝试将混合动态添加到测试中,以便再次执行测试端点中允许的每种方法(get、post、put、patch、delete)
所以,我的想法是做一个基础测试 class,如果允许的话,它会自动添加一些混合到测试端点。我可以创建将从该基础继承的实际测试 class。
代码:
from rest_framework.test import APITestCase
class GetTestMixin:
def test_get_all(self):
response = self.client.get(self.uri)
self.assertEqual(response.status_code,status.HTTP_200_OK)
class AutoMixinMeta(type):
def __call__(cls, *args, **kwargs):
allowed_methods = ['get', 'post']
# cls would be the Test class, for example TestExample
# cls.__bases__ is a tuple with the classes inherited in the Test class, for example:
# (<class 'unit_tests.endpoints.base_test.RESTTestCase'>, <class 'rest_framework.test.APITestCase'>)
bases = cls.__bases__
for method in allowed_methods:
bases += (cls.method_mixins[method.lower()],)
# Create a new instance with all the mixins
cls = type(cls.__name__, bases, dict(cls.__dict__))
return type.__call__(cls, *args, **kwargs)
class RESTTestCase(metaclass=AutoMixinMeta):
uri = None
method_mixins = {
'post': PostTestMixin,
'get': GetTestMixin,
}
class TestExample(RESTTestCase, APITestCase):
uri = reverse('somemodel-list')
我期待 test_get_all 被执行,但它没有被执行。
混合到位。我在 TestExample
中创建了一个虚拟方法并放置了一个调试器,然后检查它,如下所示:
(Pdb) self.__class__
<class 'TestExample'>
(Pdb) self.__class__.__bases__
(<class 'RESTTestCase'>, <class 'rest_framework.test.APITestCase'>, <class 'GetTestMixin'>)
问题是收集要测试的 classes 的代码永远不会“看到”class 作为测试 classes 的一个实例,或者作为a subclass of: 从测试用例继承的 class 只有在创建实例时才存在。
实现此功能的唯一方法是在导入时创建派生的 classes,并将所需的动态 classes 绑定为模块上的顶级名称。
为此,您可以取消元class,只需将语句放在模块主体中,将新的 class 或 classes 分配给名称使用globals()
。或者,如果您只需要 subclasses,而不是模块顶层,则可以将代码放在 __init_subclass__
方法中。此方法在创建 class 时调用,而不是在实例化时调用,它应该可以工作。
from rest_framework.test import APITestCase
class GetTestMixin:
def test_get_all(self):
response = self.client.get(self.uri)
self.assertEqual(response.status_code,status.HTTP_200_OK)
class RESTTestCase():
uri = None
method_mixins = {
'post': PostTestMixin,
'get': GetTestMixin,
}
def __init_subclass__(cls, *args, **kw):
super.__init_subclass__(*args, **kw)
if "Dynamic" in cls.__name__:
return
allowed_methods = ['get', 'post']
bases = list(cls.__bases__)
for method in allowed_methods:
bases.append(cls.method_mixins[method.lower()])
# Create a new instance with all the mixins
new_cls = type(cls.__name__ + "Dynamic", bases, dict(cls.__dict__))
globals()[new_cls.__name__] = new_cls
class TestExample(RESTTestCase, APITestCase):
uri = reverse('somemodel-list')
# class TestExampleDynamic is created automatically when the `class` statement above resolves