【问题标题】:Django TestCase: recreate database in self.subTest(...)Django TestCase:在 self.subTest(...) 中重新创建数据库
【发布时间】:2017-09-07 14:47:53
【问题描述】:

我需要用不同的参数测试一个函数,最合适的方法似乎是使用with self.subTest(...) 上下文管理器。

但是,该函数向 db 写入了一些内容,并最终处于不一致的状态。我可以删除我写的东西,但是如果我可以完全重新创建整个数据库会更干净。有没有办法做到这一点?

【问题讨论】:

    标签: python django testing


    【解决方案1】:

    不确定如何在 self.subTest() 中重新创建数据库,但我目前正在使用另一种技术,您可能会感兴趣。您可以使用固定装置创建数据库的“快照”,该快照基本上将复制到仅用于测试目的的第二个数据库中。我目前使用这种方法来测试我正在工作的一个大项目的代码。

    我将发布一些示例代码,让您了解这在实践中会是什么样子,但您可能需要做一些额外的研究来根据您的需要定制代码(我添加了一些链接来指导您) .

    这个过程相当简单。您将创建一个数据库副本,其中仅包含使用夹具所需的数据,这些数据将存储在 .yaml 文件中,并且只能由您的测试单元访问。

    下面是这个过程的样子:

    1. 要复制到测试数据库的列表项,以使用固定装置填充它。这只会创建一个包含所需数据的数据库,而不是愚蠢地复制整个数据库。它将存储在 .yaml 文件中。

    generate.py

        django.setup()
        stdout = sys.stdout
    
        conf = [
            {
                'file': 'myfile.yaml',
                'models': [
                    dict(model='your.model', pks='your, primary, keys'),
                    dict(model='your.model', pks='your, primary, keys')
                ]
            }
        ]
    
        for fixture in conf:
            print('Processing: %s' % fixture['file'])
            with open(fixture['file'], 'w') as f:
                sys.stdout = FixtureAnonymiser(f)
    
            for model in fixture['models']:
                call_command('dumpdata', model.pop('model'), format='yaml',indent=4, **model)
                sys.stdout.flush()
    
            sys.stdout = stdout
    
    1. 在您的测试单元中,将生成的 .yaml 文件作为夹具导入,您的测试将自动使用夹具中的数据来执行测试,同时保持主数据库不变。

    test_class.py

    from django.test import TestCase
    
    class classTest(TestCase):
    
        fixtures = ('myfile.yaml',)
    
        def setUp(self):
            """setup tests cases"""
           # create the object you want to test here, which will use data from the fixtures
    
        def test_function(self):
            self.assertEqual(True,True)
            # write your test here
    

    您可以在这里阅读更多内容:

    如果您有任何问题,因为不清楚,请尽管问,我很乐意为您提供帮助。

    【讨论】:

    • 感谢您的回复。我需要一些时间来仔细看看它。我一明白就接受。
    • 是的,当然,伙计,在您看到完整的代码正常工作之前,这还是很令人困惑的,所以有任何问题,我会尽力引导您朝着正确的方向前进。
    • @Ibolit 您是否设法解决了问题或找到了其他解决方案?
    • 我最终手动删除了数据库中的所有内容,但我也会测试这个解决方案。抱歉拖了太久。
    • 我正在使用fixtures 来设置我的测试数据库,但是经过一次大的重构之后,我不再能够加载fixtures。在使用固定装置遇到很多麻烦之后,我决定创建一个setup_db 函数并在我的测试函数顶部调用它。另外我使用faker 包来生成假数据。到目前为止,这种方法对我来说效果最好。
    【解决方案2】:

    也许我的解决方案会对某人有所帮助

    我使用事务回滚到我在测试开始时的数据库状态。

    我使用 Eric Cousineau 的 decorator function 来参数化测试

    更多关于数据库事务在 django documentation page

    import functools
    
    from django.db import transaction
    from django.test import TransactionTestCase
    from django.contrib.auth import get_user_model
    
    User = get_user_model()
    
    
    def sub_test(param_list):
        """Decorates a test case to run it as a set of subtests."""
    
        def decorator(f):
    
            @functools.wraps(f)
            def wrapped(self):
                for param in param_list:
                    with self.subTest(**param):
                        f(self, **param)
    
            return wrapped
    
        return decorator
    
    
    class MyTestCase(TransactionTestCase):
        @sub_test([
            dict(email="new@user.com", password='12345678'),
            dict(email="new@user.com", password='password'),
        ])
        def test_passwords(self, email, password):
            # open a transaction
            with transaction.atomic():
                # Creates a new savepoint. Returns the savepoint ID (sid).
                sid = transaction.savepoint()
                
                # create user and check, if there only one with this email in DB
                user = User.objects.create(email=email, password=password)
                self.assertEqual(User.objects.filter(email=user.email).count(), 1)
    
                # Rolls back the transaction to savepoint sid.
                transaction.savepoint_rollback(sid)
    

    【讨论】:

      猜你喜欢
      • 2020-01-17
      • 2016-10-27
      • 1970-01-01
      • 2021-06-07
      • 1970-01-01
      • 2012-07-14
      • 2014-10-15
      • 2011-05-04
      • 2016-08-17
      相关资源
      最近更新 更多