【问题标题】:Django test with setUpTestData doesn't keep changes between tests使用 setUpTestData 的 Django 测试不会保留测试之间的更改
【发布时间】:2019-10-04 10:51:10
【问题描述】:

类方法TestCase.setUpTestData()

上述的类级别原子块允许在类级别创建初始数据,一次用于整个 TestCase。

[...]

注意不要在您的测试方法中修改 setUpTestData() 中创建的任何对象。在类级别完成的设置工作对内存中对象的修改将在测试方法之间持续存在。

城市。 django.test.TestCase.setUpTestData

考虑这个例子:

class FoobarTest(TestCase):

    @classmethod
    def setUpTestData(cls):
        cls.post = Post()
        cls.post.stats = {}
        cls.post.save()

    def setUp(self):
        self.post.refresh_from_db()

    def test_foo(self):
        self.post.stats['foo'] = 1
        self.post.save()
        self.assertEquals(self.post.stats, {'foo': 1}) # this should fail

    def test_bar(self): # this run first cause alphabetical order
        self.post.stats['bar'] = 1
        self.post.save()
        self.assertEquals(self.post.stats, {'bar': 1})

自从

在类级别完成的设置工作对内存中对象的修改将在测试方法之间持续存在

我预计两种测试方法中的一种会失败,因为 post 对象也将具有不同的属性,并且相等应该失败。

但是这个测试没有问题通过。

如果我强制执行顺序,它实际上表现得像预期的那样:

class FoobarTest(TestCase):

    @classmethod
    def setUpTestData(cls):
        cls.post = Post()
        cls.post.stats = {}
        cls.post.save()

    def setUp(self):
        self.post.refresh_from_db()

    def _foo(self):
        self.post.stats['foo'] = 1
        self.post.save()
        self.assertEquals(self.post.stats, {'foo': 1})

    def _bar(self):
        self.post.stats['bar'] = 1
        self.post.save()
        self.assertEquals(self.post.stats, {'bar': 1})

    def test_foo_bar(self):
        self._foo()
        self._bar() # this fail

问题是:

在第一个示例中,测试方法是否以某种并行方式运行?他们真的会在一些与时间相关的巧合下失败吗?

关于 order in which tests are executed 的 Django 文档没有谈论测试方法。

this post我发现测试方法的顺序是可以改变的,但是是一个接一个,没有并行性,除非我用python manage.py test --parallel

【问题讨论】:

  • 对于今天阅读这篇文章的任何人,Django 3.2+ 现在可以为您的数据库制作一个干净的副本,因此它们被清楚地分开docs.djangoproject.com/en/3.2/topics/testing/tools/…
  • setUpTestData 在数据库不支持事务的情况下为每个测试运行调用,例如MySQL,这也可以解释这种行为

标签: python django testing


【解决方案1】:

这是我的测试,使用内存而不是数据库:

from django.test import TestCase

class Post(object):
    def __init__(self):
        self.stats = {}

    def refresh_from_db(self):
        pass

    def save(self):
        pass


class FoobarTest(TestCase):

    @classmethod
    def setUpTestData(cls):
        cls.post = Post()
        cls.post.stats = {}

    def setUp(self):
        self.post.refresh_from_db()

    def test_foo(self):
        self.post.stats['foo'] = 1
        self.post.save()
        self.assertEquals(self.post.stats, {'foo': 1})  # this should fail

    def test_bar(self):  # this run first cause alphabetical order
        self.post.stats['bar'] = 1
        self.post.save()
        self.assertEquals(self.post.stats, {'bar': 1})

这是我的结果:

    self.assertEquals(self.post.stats, {'foo': 1})  # this should fail
AssertionError: {'bar': 1, 'foo': 1} != {'foo': 1}
- {'bar': 1, 'foo': 1}
+ {'foo': 1}

将方法foo改为afoo,结果如预期:

    self.assertEquals(self.post.stats, {'bar': 1})
AssertionError: {'foo': 1, 'bar': 1} != {'bar': 1}
- {'bar': 1, 'foo': 1}
+ {'bar': 1}

所以也许这是一个数据库问题?

在您的断言中,您正在检查内存中的对象:如果 save 失败,refresh_from_db 返回起始空对象,因此下一个检查通过。

尝试在save 之后取回数据,然后检查它们。

【讨论】:

  • 在示例中,如果save 失败,我预计会收到异常。同样在“真实”代码中,我检查了这一点并且没有保存错误。
  • 我认为收到异常并且您遇到的所有这些都属于模型实现或某些数据库/驱动程序问题。
猜你喜欢
  • 1970-01-01
  • 2019-10-04
  • 1970-01-01
  • 1970-01-01
  • 2015-08-10
  • 1970-01-01
  • 2021-09-20
  • 1970-01-01
  • 2016-12-27
相关资源
最近更新 更多