【问题标题】:Same test for different states of the same object without persisting changes对同一对象的不同状态进行相同测试,而无需持续更改
【发布时间】:2018-05-20 17:35:42
【问题描述】:

我正在尝试在单个 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新鲜 实例,就像刚刚调用了test 方法一样,我们直接从固定装置获取数据。

    李>
  • 如果断言语句失败,我将能够看到它是哪一个,但由于for,我将无法确定 what 案例(状态)失败环形。我可以在test 方法中try-except _test_obj_ 调用,但我无法判断什么断言失败。

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

【问题讨论】:

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


    【解决方案1】:
    1. 在完成对象后简单地回滚。

    2. 可以在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
    

    【讨论】:

      【解决方案2】:

      这个答案可以改进。您可以简单地为原子块设置回滚,而不是强制回滚错误。见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
      

      【讨论】:

        猜你喜欢
        • 2016-05-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-12-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-16
        相关资源
        最近更新 更多