Python 有没有更快的方法为Django视图编写类似的测试用例?
基本上,我意识到我正在为多个模型的类似URL编写相同的测试用例test_update_,其中只包含_1_字段Python 有没有更快的方法为Django视图编写类似的测试用例?,python,django,python-unittest,parameterized-tests,Python,Django,Python Unittest,Parameterized Tests,基本上,我意识到我正在为多个模型的类似URL编写相同的测试用例test_update_,其中只包含_1_字段 from django.test import RequestFactory, TestCase class BaseApiTest(TestCase): def setUp(self): superuser = User.objects.create_superuser('test', 'test@api.com', 'testpassword') self.facto
from django.test import RequestFactory, TestCase
class BaseApiTest(TestCase):
def setUp(self):
superuser = User.objects.create_superuser('test', 'test@api.com', 'testpassword')
self.factory = RequestFactory()
self.user = superuser
self.client.login(username=superuser.username, password='testpassword')
class SomeModelApiTests(base_tests.BaseApiTest):
def test_update_with_only_1_field(self):
"""
Tests for update only 1 field
GIVEN the following shape and related are valid
WHEN we update only with just 1 field
THEN we expect the update to be successful
"""
shape_data = {
'name': 'test shape',
'name_en': 'test shape en',
'name_zh_hans': 'test shape zh hans',
'serial_number': 'test shape serial number',
'model_name': {
'some_field': '123'
}
}
data = json.dumps(shape_data)
response = self.client.post(reverse('shape-list-create'), data, 'application/json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
some_model = response.data['some_model']
new_some_field = '12345'
data = json.dumps({'some_field': new_some_field, 'id': response.data['some_model']['id']})
response = self.client.put(reverse('some-model', args=[some_model['id']]), data, 'application/json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(new_some_field, response.data['some_field'])
我需要这样做超过10次。我已经这样做了
每一次的唯一区别是以下短语:一些模型、一些模型和一些字段
我想知道有没有更快的方法
我可以从两个方面进行抽象思考:
在文本编辑器中创建一个模板,以某种方式生成最终的测试用例,然后复制并粘贴。虽然我可以切换到另一个文本编辑器,但我正在使用sublime text 3
有一种方法可以编写更多的代码,将这个测试用例转换成单个测试类可以调用的行为类。又名作文
哪一个更有意义,或者有不同的方法
请注意,BaseApi类也被其他没有重复测试用例方法的测试类继承。您可以创建一些要测试的\u模型的列表/目录,并为每个\u模型项使用子测试
my_list_of_model = [FirstModel, SecondModel]
for my_model in my_list_of_model:
with subTest(model=mymodel):
# Testing model here
如果您希望为每个模型使用不同的测试用例,我认为多重继承是一种可行的方法:
class BaseApiTestCase(TestCase):
def setUp():
# Setup stuff
class RepetitiveTestCaseMixin:
# Class to do the repetitive stuff
def test_update_should_work(self):
# Do some thing with self.model and self.field here
class ModelTestCase(BaseApiTestCase, RepetitiveTestCaseMixin):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.model = MyModel
cls.field = 'some_field'
我想您需要的是参数化测试,标准unittest可以通过包来实现: 将产生:
test_update_with_only_1_field_0_case1 (t.SomeModelApiTests) ... m1 f1 nf1
ok
test_update_with_only_1_field_1_case1 (t.SomeModelApiTests) ... m2 f2 nf2
ok
pytest测试框架具有更好的内置支持,值得一看。我所从事的项目有时会在需要重复测试时使用mixin+定制挂钩。而像“形状列表创建”这样的端点可能会发生更改/重构 问题示例:
class TestUpdateWithOnly1FieldMixin(object):
some_model = None
some_field = None
some_model2 = None
def get_some_model(self):
return self.some_model
def get_some_field(self):
return self.some_field
def get_some_model2(self):
return self.some_model2
def test_update_with_only_1_field(self):
some_model = self.get_some_model()
# represents some-model in example
some_model2 = self.get_some_model2()
some_field = self.get_some_field()
shape_data = {
'name': 'test shape',
'name_en': 'test shape en',
'name_zh_hans': 'test shape zh hans',
'serial_number': 'test shape serial number',
'model_name': {
some_field: '123'
}
}
data = json.dumps(shape_data)
response = self.client.post(reverse('shape-list-create'), data, 'application/json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
some_model_data = response.data[some_model]
class SomeModelApiTests(base_tests.BaseApiTest, TestUpdateWithOnly1FieldMixin):
some_model = 'choose your model'
some_field = 'some_field'
some_model2 = 'some-model'
def get_some_field(self):
# Do customization
return 'some-field after customize'
如何分割定制挂钩以及在mixin中放入什么等都是根据情况而定的。
在我看来,目标是使实际的测试用例易于遵循。可能将post shape list create移动到一个单独的函数中,因为它可能与该测试用例并不相关
另一个例子是,在定制方面有点过火,但只是为了给出一个想法
class TestWithGoodNameMixin(object):
some_model = None
some_field = None
# "Customization hooks"
def get_shape_data(self):
return {self.some_field: 'x'}
def create_model(self, shape_data):
response = self.client.post(reverse('shape-list-create'), shape_data,
'application/json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
return response[self.some_model]
def create_put_data(self, some_model_data):
# Add default implementation
pass
# .....
def test_update_with_only_1_field(self):
shape_data = self.get_shape_data()
some_model_data = self.create_model(shape_data)
data = self.create_put_data(some_model_data)
response = self.put_data(data)
self.assert_put_response(response)
您可以使用pytest包进行单元测试。
它非常简单,易于使用
@pytest.mark.parametrize decorator可用于实现该功能
参数化测试用例的示例如下:
import pytest
class SampleTesting(object):
data_for_test = [
('{inputdata1:value1}','output1'),
('{inputdata1:value2}','output2')
]
@pytest.mark.parametrized('input_data, expected_output', data_for_test)
def test_sample_function(self, input_data, expected_output):
response = function_to_be_tested(input_data)
assert response == expected_output
你可以在'
您还可以使用@pytest.fixture decorator来设置测试函数。如果我听起来很迂腐,很抱歉,但是您的第二个解决方案不是更像多重继承而不是组合吗?实际上,baseapi类是由其他没有重复测试用例的模型测试类继承的。这将如何改变第二种解决方案?这确实是多重继承,我编辑了我的答案。为了回答您的第二个评论,您应该只在mixin中移动您的test\u update\u should\u work和其他共享方法,而不是在BaseApiTestCase中,因此您的ModelTestCase看起来像类ModelTestCaseBaseTestCase,RepetitiveTestCaseMixin。。。因此,您可以选择是否继承RepetitiveTestCaseMixin编辑的我的答案。我如何使用类/实例属性将“某个字段”的可变值传递到混合方法中?在我的回答中,您可以看到我在子类中定义了cls.model,并在RepetitiveTestCaseMixin中访问它,在这里使用self.model做一些事情。您可以使用这种方式或更好的方式根据需要设置多个值,只需类属性。。。
import pytest
class SampleTesting(object):
data_for_test = [
('{inputdata1:value1}','output1'),
('{inputdata1:value2}','output2')
]
@pytest.mark.parametrized('input_data, expected_output', data_for_test)
def test_sample_function(self, input_data, expected_output):
response = function_to_be_tested(input_data)
assert response == expected_output