Brian
Brian

Reputation: 1391

Django - Objects created by code under test do not appear in test database

DON'T WASTE YOUR TIME READING THIS QUESTION. IT HAS BEEN ANSWERED BELOW.

My settings.py contains:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': 'foo.db',
        'TEST_NAME': 'thetest.db'
    }
}

In the test code is this line:

allShoes = models.Shoe.objects.filter()

allShoes should contain objects, because the table is populated by views.py, but it's empty in the code. I also put a set_trace() in the test code to pause it and verified with the sqlite3 program that foo.db contains the objects, not thetest.db.

I have alternately tried deriving my model class, Shoe, from django.test.TestCase and from django.test.TransactionTestCase. Neither worked.

I'm using:

>>> django.VERSION
(1, 4, 3, 'final', 0)

and

(venv)bmac:ol b$ python
Python 2.7.2 (default, Jun 20 2012, 16:23:33) 
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin

Have any ideas about what I'm doing wrong?

Edit: Just to clarify, foo.db is empty, having just beforehand been created by syncdb, before the test is run and thetest.db does not exist. My test is a Selenium test which causes a view (part of the code under test) to be called and then makes two clicks on the page. Each click has an AJAX handler that calls another view; that view (more code under test) creates an entry in the DB. So, at the end, there should be two clicks in the DB, before the DB is destroyed by the test runner.

Edit: I removed TEST_NAME from DATABASES to make the problem simpler, though I've seen no difference in behavior. While running the test, from my view code I can run:

models.Shoe.objects.using('default').all()

and see the objects. However, from my test routine, the same statement produces an empty list.

Upvotes: 0

Views: 1118

Answers (2)

Brian
Brian

Reputation: 1391

I have not confirmed this solution yet, but don't want people spending their time reading this question. I believe that the problem arose because I was running the Django development server from my test code so that I could simulate connection flakiness. That caused the production database to be used, and explained why the test database was empty. D'oh.

Upvotes: 0

Austin Phillips
Austin Phillips

Reputation: 15776

When the Django test runner executes, the production database is not touched. In our question, foo.db is your production database and Django make sure that this is not touched when you run your unit tests. Instead, it will create a new database just for the purposes of running your tests. Normally this would be an in-memory database for sqlite, but since you've specified TEST_NAME in settings.py, the test database will be an on-disk database named thetest.db.

Unless you call your view code in your test to populate a record during the test, there will be nothing in thetest.db.

A test case might look something like this.

from django.test import TestCase

class MyTest(TestCase):

    def test_something(self):
        # Simulate a browser POST which would populate an object in Shoes.
        # When the test starts, the db is empty.
        response = self.client.post('/shoe/add/', {
            # Post data here.
        })

        self.assertEqual(
            1,
            models.Shoe.objects.count())

Upvotes: 1

Related Questions