Django test case db giving inconsistent responses, caching or transaction culprit?

与世无争的帅哥 提交于 2019-12-23 15:05:19

问题


I am seeing some really surprising and frustrating behavior with Django testing. Model objects are being "found" by a related lookup, but no model objects exist. (I apologize for the weird description here...the behavior is bizarre enough that I don't know quite how to describe it. Do the objects exist? Do I exist? Do you??)

I need them to exist, so I have a method in place that creates them if they don't exist. The problem is that on one line, Django finds that they do exist, and therefore they are not created...and then on the next line we can confirm that no such objects exist.

My tests are giving Errors in test_something() related to the absence of the necessary TaskMetadata object.

#the model
class TaskMetadata(models.Model):
    task = models.OneToOneField(ContentType)
    ...

#the test
class SimpleTest(TestCase):
    def setUp(self):
        some_utility_function()

    def test_something(self):
        ...something that requires TaskMetadata...

def some_utility_function():
    task = ...whatever...
    ctype = ContentType.objects.get_for_model(task)
    try:
        ctype.taskmetadata
    except TaskMetadata.DoesNotExist:
        ...create TaskMetadata...
        print "Created TaskMetadata object for %s" % task.__name__
    else:
        print "TaskMetadata object already exists for %s" % task.__name__
        print ctype.taskmetadata
        print "ALL OF THEM!! %s" % TaskMetadata.objects.all()

and the printed result of some_utility_function():

TaskMetadata object already exists for SomeTask
some task
ALL OF THEM!! []     # <-- NOTE EMPTY QUERYSET

In summary: "Yes, TaskMetadata object exists. Yes, TaskMetadata object exists. No, there are no TaskMetadata objects at all!!"

So, seriously, what on earth is going on here? Is this a cache problem? I tried clearing the cache (wild guess; I don't have CACHES configured in settings.py)

def setUp(self):
    cache.clear()
    some_utility_function()

Does not help. Transactions maybe? I'm stumped. How do I even debug this?

UPDATE: See a minimal django project that replicates the issue here.

When the first testcase runs, TaskMetadata.objects.all() is NOT an empty queryset (it is in fact populated with objects, as I would expect); when the second testcase (exactly the same as the first) runs, it is empty.

I suspect this has something to do with database flushing between testcases that is clearing out the TaskMetadata objects, but the related lookup is cached, and so the next time some_utility_function() is called for the next testcase, it doesn't create any TaskMetadata objects. 1) Is that plausible? 2) How to work around it? 3) This is a Django bug, right?

Django bug ticket


回答1:


In your tearDown method you need to call ContentType.objects.clear_cache(). This is because Django caches calls to ContentType.objects.get_for_model. Having a one-to-one to content type is a bit weird, so I don't think django needs to make any changes for this, especially as it should be a one line fix for you.




回答2:


The problem here is the "finally" clause.

A finally clause is always executed before leaving the try statement, whether an exception has occurred or not.

http://docs.python.org/2/tutorial/errors.html

So, the finally clause containing the print statements will always be executed.



来源:https://stackoverflow.com/questions/21631596/django-test-case-db-giving-inconsistent-responses-caching-or-transaction-culpri

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!