对同一对象的不同状态进行相同的测试,而无需持久更改
Same test for different states of the same object without persisting changes
我正在尝试 运行 在单个 obj
上进行完全相同的测试,这是一个 models.Model
实例并且与其他模型有一些关系。我不想在那个实例中保留更改,所以实际上我想要回滚事务的 tearDown
方法的相同效果。
为了说明这一点:
class MyTestCase(django.test.TestCase):
def test():
# main test that calls the same test using all
# different states of `obj` that need to be tested
# different values of data that update the state of `obj`
# with state I simply mean the values of `obj`'s attributes and relationships
data = [state1, state2, state3]
for state in data:
obj = Obj.objects.get(pk=self.pk) # gets that SINGLE object from the test db
# applies the state data to `obj` to change its state
obj.update(state)
# performs the actual test on `obj` with this particular state
self._test_obj(obj)
def _test_obj(self, obj):
self.assertEqual(len(obj.vals), 10)
self.assertLess(obj.threshold, 99)
# more assert statements...
这个设计有两个问题:
obj
上的更改会保留在测试数据库中,因此在下一次迭代中数据将被 污染。我想回滚这些更改并获得 obj
的 fresh 实例,就像刚刚调用 test
方法一样,我们直接从固定装置获取数据.
如果断言语句失败,我将能够看到它是哪一个,但我将无法确定什么情况(状态)由于 for
循环而失败。我可以 try-except
_test_obj_
在 test
方法中调用,但我无法告诉 什么 断言失败。
django.test
是否提供任何工具来 运行 对同一模型的不同状态进行相同的测试?如果没有,我如何在解决上述两点的同时做我想做的事情?
完成对象后简单回滚。
您可以在python 3.4+
中使用新的subTest
您的代码应如下所示:
class TestProductApp(TestCase):
def setUp(self):
self.product1 = ...
def test_multistate(self):
state1 = dict(name='p1')
state2 = dict(name='p2')
data = [state1, state2]
for i, state in enumerate(data):
with self.subTest(i=i):
try:
with transaction.atomic():
product = Product.objects.get(id=self.product1.id)
product.name = state['name']
product.save()
self.assertEqual(len(product.name), 2)
raise DatabaseError #forces a rollback
except DatabaseError:
pass
print(Product.objects.get(id=self.product1.id)) #prints data created in setUp/fixture
这个答案可以改进。您可以简单地为原子块设置回滚,而不是强制回滚错误。参见 set_rollback()
class TestProductApp(TestCase):
def setUp(self):
self.product1 = ...
def test_multistate(self):
state1 = dict(name='p1')
state2 = dict(name='p2')
data = [state1, state2]
for i, state in enumerate(data):
with self.subTest(i=i):
with transaction.atomic():
product = Product.objects.get(id=self.product1.id)
product.name = state['name']
product.save()
self.assertEqual(len(product.name), 2)
transaction.set_rollback(True) # forces a rollback
print(Product.objects.get(id=self.product1.id)) #prints data created in setUp/fixture
我正在尝试 运行 在单个 obj
上进行完全相同的测试,这是一个 models.Model
实例并且与其他模型有一些关系。我不想在那个实例中保留更改,所以实际上我想要回滚事务的 tearDown
方法的相同效果。
为了说明这一点:
class MyTestCase(django.test.TestCase):
def test():
# main test that calls the same test using all
# different states of `obj` that need to be tested
# different values of data that update the state of `obj`
# with state I simply mean the values of `obj`'s attributes and relationships
data = [state1, state2, state3]
for state in data:
obj = Obj.objects.get(pk=self.pk) # gets that SINGLE object from the test db
# applies the state data to `obj` to change its state
obj.update(state)
# performs the actual test on `obj` with this particular state
self._test_obj(obj)
def _test_obj(self, obj):
self.assertEqual(len(obj.vals), 10)
self.assertLess(obj.threshold, 99)
# more assert statements...
这个设计有两个问题:
obj
上的更改会保留在测试数据库中,因此在下一次迭代中数据将被 污染。我想回滚这些更改并获得obj
的 fresh 实例,就像刚刚调用test
方法一样,我们直接从固定装置获取数据.如果断言语句失败,我将能够看到它是哪一个,但我将无法确定什么情况(状态)由于
for
循环而失败。我可以try-except
_test_obj_
在test
方法中调用,但我无法告诉 什么 断言失败。
django.test
是否提供任何工具来 运行 对同一模型的不同状态进行相同的测试?如果没有,我如何在解决上述两点的同时做我想做的事情?
完成对象后简单回滚。
您可以在python 3.4+
中使用新的subTest
您的代码应如下所示:
class TestProductApp(TestCase):
def setUp(self):
self.product1 = ...
def test_multistate(self):
state1 = dict(name='p1')
state2 = dict(name='p2')
data = [state1, state2]
for i, state in enumerate(data):
with self.subTest(i=i):
try:
with transaction.atomic():
product = Product.objects.get(id=self.product1.id)
product.name = state['name']
product.save()
self.assertEqual(len(product.name), 2)
raise DatabaseError #forces a rollback
except DatabaseError:
pass
print(Product.objects.get(id=self.product1.id)) #prints data created in setUp/fixture
这个答案可以改进。您可以简单地为原子块设置回滚,而不是强制回滚错误。参见 set_rollback()
class TestProductApp(TestCase):
def setUp(self):
self.product1 = ...
def test_multistate(self):
state1 = dict(name='p1')
state2 = dict(name='p2')
data = [state1, state2]
for i, state in enumerate(data):
with self.subTest(i=i):
with transaction.atomic():
product = Product.objects.get(id=self.product1.id)
product.name = state['name']
product.save()
self.assertEqual(len(product.name), 2)
transaction.set_rollback(True) # forces a rollback
print(Product.objects.get(id=self.product1.id)) #prints data created in setUp/fixture