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

时间:2017-12-06 18:23:36

标签: python django python-2.7 testing django-1.8

我正在尝试在objmodels.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实例,就像刚刚调用test方法一样,我们直接从灯具中获取数据。

  • 如果断言语句失败,我将能够看到它是哪一个,但由于{{1},我将无法确定 案例(状态)失败循环。我可以在for方法中try-except调用_test_obj_,但我无法告诉 断言失败。

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

2 个答案:

答案 0 :(得分:0)

  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
    

答案 1 :(得分:0)

此答案可以改善。您不必为错误块强制回滚,而只需为原子块设置回滚。参见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