1

我为我的 Django 应用程序编写的测试在我使用 SQLite 的初始开发过程中运行良好。现在我准备好部署我已经设置了一个 MySQL 服务器(因为这就是我将要部署的)但是现在我的一些测试失败了。

最后,当我手动测试功能时,失败的测试不会失败。

会发生什么?

我没有做任何不寻常的事情,所有的视图都会做一些数据库恶作剧并返回响应。没有任何与时间相关的东西(没有线程或任何东西)。

这些测试都继承自 django.test.TestCase 并且我没有使用任何固定装置。

这是一个失败的测试示例。

class BaseTest(TestCase):
    def setUp(self):
        super(BaseTest, self).setUp()

        self.userCreds = dict(username='test', password='a')

        # Create an admin user
        admin = models.User.objects.create_superuser(
            email='', username='admin', password='a')

        # Create a user and grant them a licence
        user = models.User.objects.create_user(
            email='some@address.com', first_name="Mister",
            last_name="Testy", **self.userCreds)

        profile = models.getProfileFor(user)
        node = profile.createNode(
            '12345', 'acomputer', 'auser',
            'user@email.com', '0456 987 123')

        self.node = node

class TestClientUIViews(BaseTest):
    def test_toggleActive(self):
        url = reverse('toggleActive') + '?nodeId=%s' % self.node.nodeId

        self.assertFalse(self.node.active)

        # This should fail because only authenticated users can toggle a node active
        resp = self.client.get(url)
        self.assertEqual(resp.status_code, 403)
        self.assertFalse(self.node.active)

        # Login and make sure visiting the url toggles the active state
        self.client.login(**self.userCreds)
        resp = self.client.get(url)
        self.assertEqual(resp.status_code, 200)
        self.assertTrue(self.node.active)

        resp = self.client.get(url)
        self.assertEqual(resp.status_code, 200)
        self.assertFalse(self.node.active)

这是模型的样子:

class Node(models.Model):
    @property
    def active(self):
        '''
        Activation state gets explictly tracked in its own table but is
        exposed as a property for the sake of convenience
        '''
        activations = NodeActivation.objects \
            .filter(node=self) \
            .order_by('-datetime')

        try:
            return activations[0].active
        except IndexError:
            return False

    @active.setter
    def active(self, state):
        if self.active != state:
            NodeActivation.objects.create(node=self, active=state)

class NodeActivation(models.Model):
    node = models.ForeignKey("Node")
    datetime = models.DateTimeField(default=datetimeM.datetime.now)
    active = models.BooleanField(default=False)

我的本地 MySQL 是 5.5.19(所以它使用 InnoDB),但我在使用 5.1.56 的部署服务器上遇到了同样的故障。无论存储引擎如何,测试都会失败。

正如我在开头提到的,如果我切换回使用 SQLite 数据库,所有测试都会返回通过。

4

3 回答 3

2

现在揭示了更多实际代码,我将提供以下假设来说明此测试失败的原因。

NodeActivation模型不正确。该datetime字段应为:

datetime = models.DateTimeField(auto_now=True)

在模型定义中使用datetime.datetime.now()只会被评估一次。

每次设置者创建新NodeActivation记录时,都会使用相同的日期/时间创建记录。即NodeActivation模型首次评估的日期/时间。

你的 getter 只返回一个结果。但由于两个激活记录具有相同的日期/时间,因此排序可能取决于数据库后端。测试结束时,您的数据库中将有两条NodeActivation记录,返回的一条是不确定的。

于 2013-02-05T06:14:04.593 回答
1

通过将 Node 模型类的 active 属性更改为:

@property
def active(self):
    '''
    Activation state gets explictly tracked in its own table but is
    exposed as a property for the sake of convenience
    '''
    activations = NodeActivation.objects \
        .filter(node=self) \
        .order_by('-id')

    try:
        return activations[0].active
    except IndexError:
        return False

问题消失了。

注意order_by呼叫的变化。

记录的创建速度如此之快,以至于按日期时间排序不是确定性的,因此行为不稳定。而且我猜 SQLite 只是比 MySQL 慢,这就是为什么将它用作后备数据库时它不是问题的原因。

注意:感谢Austin Phillips的提示(查看他的回答中的评论)

于 2013-02-05T07:14:34.857 回答
0

我有一个类似的问题(不确定是否相同),使用设置方法从 SQLite 到 PostgreSQL,就像你对初始数据库对象使用的那样。

例子::

def setUp(self):
   user = User.objects.create_user(username='john', password='abbeyRd', email='john@thebeatles.com')
   user.save()

我发现这在 SQLite 上可以正常工作,但是在 PostgreSQL 上我遇到了数据库连接失败(它仍然会像你说的那样构建数据库,但是如果没有连接错误就无法运行测试)。

事实证明,解决方法是按如下方式运行您的设置方法:

@classmethod
def setUpTestData(cls):
    user = User.objects.create_user(username='john', password='abbeyRd', email='john@thebeatles.com')
    user.save()

我不记得为什么这个有效而另一个无效的确切原因,但它与与数据库的setUp(self)连接setUpTestData(cls)有关实例化,但我可能没有完美的细节。我真正知道的是它有效!

希望有所帮助,不确定它是否解决了您的确切问题,但我花了好几个小时才弄清楚,所以我希望它对您和将来的其他人有所帮助!

于 2018-02-15T22:29:29.243 回答