对同一对象的不同状态进行相同的测试,而无需持久更改

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...

这个设计有两个问题:

django.test 是否提供任何工具来 运行 对同一模型的不同状态进行相同的测试?如果没有,我如何在解决上述两点的同时做我想做的事情?

  1. 完成对象后简单回滚。

  2. 您可以在python 3.4+

  3. 中使用新的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