【问题标题】:How to update unittests when migrating from sqlite to postgres (django)从 sqlite 迁移到 postgres (django) 时如何更新单元测试
【发布时间】:2018-10-09 00:24:55
【问题描述】:

我有一个较大的 Django 项目,其中包含许多视图/模型。我最近将我的项目从 sqlite3 迁移到本地的 postgres,并计划进一步扩展(将 postgres 放在单独的机器上等)。

当我从 sqlite 迁移到 postgres 时,我关注了 these instructions,它似乎运行良好。 (即,我正在运行的应用程序看起来与数据库是 sqlite 时相同)

我的问题是这样的:当我运行我以前编写的单元测试时,第一个单元测试有效,所有进行中的单元测试都失败了。单独地,单元测试工作正常。我在 stackoverflow 上看到了一些 other posts 解决了这个问题,但解决方案非常不清楚。如何为我的单元测试重新设计我的 setUp()/ teardown() 方法,以便它们与我新迁移的 postgres 数据库一起通过?我需要完全重写所有单元测试吗?

我见过pytest-postgresql library,尽管我不完全确定如何根据此修改我的单元测试。

我的测试套件设置有用于测试视图的不同类。例如,

class View1Tests(TestCase):
    def setUp(self):
        c1 = Category.objects.create(id=55555, leaf_node_name="Test Category 1")
        c2 = Category.objects.create(id=12345, leaf_node_name="Test Category 2")

        s1 = Search.objects.create(category=c1, username="testuser")
        s2 = Search.objects.create(category=c2, username="testuser2")


    def test_view1_success(self):
         #blablabla

    def test_view1_fail(self):
         #blablabla

    def test_view1_something(self):
         #blablabla

我收到这样的错误:

appname.models.DoesNotExist:搜索匹配查询不存在。

同样,当 sqlite3 是数据库时,所有这些单元测试都运行得非常好。我认为这是 postgres 测试设置的问题?但我不知道从哪里开始。任何帮助将不胜感激!

【问题讨论】:

  • 可能是一个愚蠢的问题,但大概您的测试类扩展了django.test.TestCase 并且您正在使用python manage.py test 运行您的测试?
  • @WillKeeling 我的测试扩展了 django.test.TestCase。但是,我正在运行 pytest 来运行所有测试。不过,运行 python manage.py test 也会引发相同的错误。
  • @HeidiLyons:你设法解决了这个问题吗?我现在在同一个地方。如果你能发布对你有用的东西,那就太好了!谢谢。
  • 从 sqlite 迁移到 postgresql 时,我遇到了同样的错误。如果我弄清楚问题是什么,我会发布回复
  • 我想我找到了解决方案。解决方案发布在下面。

标签: python django postgresql python-unittest pytest-django


【解决方案1】:

我想我终于找到了问题所在。尝试通过默认主键(例如MyModel.objects.get(pk=1)MyModel.objects.get(id=1))获取对象时会出现此问题。我的假设是 Postgres 使用串行数据类型作为 AutoField,增量的值取决于 Postgres 生成的序列。

我找到的解决方案非常简单。通过对该对象具有唯一属性的属性进行获取,或者获取所有对象并使用列表索引进行过滤。后一种方法应该不会太麻烦,因为在大多数情况下,会创建几个模型实例。

这是一个完整的例子

# models.py
class Book(models.Model):
    isbn = models.CharField(
        max_length=13,
        primary_key=True  # uniqueness is enforced
    )
    book_name = models.CharField(
        max_length=128,
        unique=True  # another unique field
    )
    author_count = models.IntegerField()
    book_genre = models.CharField(max_length=64)


# tests.py
class MyTest(TestCase):
    @classmethod
    def setUpTestData(cls):
        # first object
        Book.objects.create(
            isbn='10101',
            book_name='Binary Code',
            author_count=1,
            book_genre='Fiction'
        )

        # second object
        Book.objects.create(
            isbn='314159',
            book_name='Life of Pi',
            author_count=1,
            book_genre='Philosophy'
        )

    def setUp(self):
        self.book1 = Book.objects.all()[0]
        # or self.book1 = Book.objects.get(isbn='10101')
        # or self.book1 = Book.objects.get(book_name='Binary Code')
        self.book2 = Book.objects.all()[1]
        # or self.book2 = Book.objects.get(isbn='314159')
        # or self.book2 = Book.objects.get(book_name='Life of Pi')

    def test_something(self):
        # lastly, since `setUp` is called before every test_* method
        # you can just access the instance's attributes without calling `get`
        # e.g:
        self.assertEqual(self.book1.book_genre, 'Fiction')

    def test_something_else(self):
        # you an also reload the instance using `refresh_from_db`
        # after making changes
        Book.objects.filter(author_count=1).update(book_genre='Fiction')
        self.book2.refresh_from_db()
        self.assertEqual(self.book2.book_genre, 'Fiction')

【讨论】:

  • 为什么会发生这种情况?
  • 我有一个问题...我想测试需要提供模型 ID 的 PATCH 和 DELETE 方法。我该如何测试,id有点随机。以前,我使用 sqlite,但在迁移到 postgres 后,这些测试开始失败。
  • @GoutamBSeervi 如我的回答中所述,使用列表索引来获取记录,而不是通过 ID 获取。这应该允许您测试其他方法。
  • 工作量很大。我将不得不重写我所有的测试。我已经被这个错误困了一天???
  • 我能够通过用 TransactionTestCase 替换 TestCase 来解决这个问题,现在我的测试工作正常......但他们现在需要更多时间。 xD 以前需要大约一秒钟..现在是 70 秒
猜你喜欢
  • 2019-05-31
  • 2016-08-24
  • 2021-09-21
  • 2016-07-19
  • 2021-01-11
  • 2014-07-21
  • 2016-03-30
  • 2015-01-02
  • 1970-01-01
相关资源
最近更新 更多