每次测试后如何重置Django测试数据库ID?

时间:2018-07-24 17:07:56

标签: python django database shell docker

我有一个django应用,正在对其进行一些单元测试。因此,我遇到的问题不是当一个测试插入到测试数据库中时。这是随后的测试。由于每个测试都没有保存事务,因此很好不会显示来自先前测试的条目,尽管自动增量ID的增加似乎就好像数据库中还有条目一样。我需要解决此问题,因为我在无法控制为其分配ID的地方插入了更多数据,因此需要能够获取此特定数据进行测试。如果我对要捕获对象的代码进行硬编码,则每次添加新测试时都必须更改代码,这是不理想的。

我正在运行多个测试,但为简单起见,我将显示两个。

from django.test import TestCase
from app.models import Model

class VersionMerge(TestCase):
   fixtures = ['initial_test_data.json']

   def test_model_test1(self):
       *Insert new data*
       *grab new data in*
       *Check data*

   def test_model_test2(self):
       *Insert new data*
       *grab new data*
       *Check data*

问题出现在 test_model_test2 中,当我尝试获取新数据时,我必须打印出该对象以查看ID才能获取它。

对于如何在实际数据库上解决此问题,我没有解决方案,但对于测试数据库却没有解决方案。对于我来说,我需要能够连接到Docker容器并运行psql命令以重置table_id_seq。

docker exec -t  $CONTAINER_ID psql --dbname=test_database_name -username=user -c "SELECT setval('modelName_appName_id_seq', 2, true)"

这将转到表并将最后一个id值设置为2,以使下一个id为3。但是,每当我尝试使用

从python内部运行命令时,
cmd = "command above"
os.system(cmd)

,当我运行它时,出现以下错误。

sh: 1: docker: not found
sh: 1: docker: not found

在此方面寻求任何帮助,无论是解决问题的新方法还是我的改进。

TLDR;我需要能够修改django单元测试创​​建的数据库中的数据。

4 个答案:

答案 0 :(得分:0)

与数据库有交互作用的测试不称为单元测试。它们称为集成测试。 如果您希望每次都重置数据库,建议使用django测试用例:

from django.test import TestCase

答案 1 :(得分:0)

您正在使用Fixtures文件-将所需的任何数据放入其中;然后根据需要在测试中对其进行编辑。

尽管如此,这很难维护。我认为-还有更好的选择,可能会更符合您的预期。

最好使用factory_boy之类的东西,并在实例化您提供的伪数据时生成模型(和相关的外键)。

这样,您就可以准确地确切知道正在测试什么,并且它完全独立于其他所有内容。令人高兴的是,有了factory_boy,您将拥有一个factories.py文件,与使用某些灯具相比,您可以更轻松地保持最新状态。

还有其他选项,例如Mixermodel_mommy,尽管我只有factory_boymixer的经验。

使用factory_boy可能看起来像这样:

   def test_model_test1(self):
       factory.ModelFactory(
       some_specific_attribute='some_specific_value'
       )
       model = Model.objects.all().first()
       # Test against your model

答案 2 :(得分:0)

如果需要测试以重置主键序列,则可以发出RawSQL查询。 this StackOverflow question给出了确切的操作方法。

如果您使用的是pytest,则可以使用一个更简单的选项。我们在所有Django项目中都使用pytest和pytest-django,这使测试变得轻而易举。 pytest-django提供a database fixture that can take a boolean parameter to reset the sequences。像这样使用它:

@pytest.mark.django_db(transaction=True, reset_sequences=True)
def mytest():
   [...]

答案 3 :(得分:0)

我通过将 TestCase 替换为 TransactionTestCase 并设置 reset_sequences=True 来实现此目的。但是测试运行速度较慢。

from django.test import TransactionTestCase

class ViewTest(TransactionTestCase):
    reset_sequences = True

    def test_view_redirects(self):
       ...

这是doc