ensam är stark

Django testrunner

april 20, 2010

Det är nu dags att introducera den nörd som bor inom mig och hur kan man på bättre sätt göra det än att dela med sig av sin senaste kod-snutt?

På sistone har jag suttit och pillat en hel del med NoSQL-databaser och fastnat för mongodb. Jag ska inte gå in djupare på fenomenet utan istället fokusera på detta inlägg.

Problemet jag stötte på igår när jag började min migration från postgresql till mongodb för denna blogg som du för tillfället läser, stötte jag på ett problem med mina tester i Django. Det visade sig efter lite funderingar att django inte initialiserade en mongodb testdatabas utan en sqlite3-databas som helt enkelt lät mina test passera (när de inte skulle).

För att ta mig runt problemet blev jag tvungen att modifiera django's standard testrunner en aning och följande är vad jag åstadkom.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
from django.test.simple import DjangoTestSuiteRunner
from django.test import TransactionTestCase

from mongoengine import connect

class TestRunner(DjangoTestSuiteRunner):
    def setup_databases(self, **kwangs):
        db_name = 'testsuite'
        connect(db_name)
        print 'Creating test-database: ' + db_name

        return db_name

    def teardown_databases(self, db_name, **kwargs):
        from pymongo import Connection
        conn = Connection()
        conn.drop_database(db_name)
        print 'Dropping test-database: ' + db_name

class TestCase(TransactionTestCase):
    def _fixture_setup(self):
        pass

En förklaring

Till att börja med importerar jag DjangoTestSuiteRunner som TestRunner ärver av där databas-setupen skrivs över för att skapa oss en mongodb test-databas via setup_databases samt att ta bort databasen när testet är slutgjort via teardown_databases.

Till en början trodde jag att det var vad som krävdes för att få allt att fungera men det visar sig att django.test.TestCase (som vanligtvis används vid tester) gör några extra kontroller för att se att databasen är tillgänglig. Därav ärver jag TransactionTestCase (som är den klass som TestCase ärver av) och skippar kontrollen i _fixture_setup.

Hur använder jag denna testrunner?

Till att börja med fungerar denna testrunner enbart tillsammans med mongodb och mongoengine. När du har detta installerat sparar du ner testrunnern i valfri fil och väljer att använda en custom runner i settings.py via

# Förutsätter att testrunner.py ligger i samma katalog-nivå som settings.py
TEST_RUNNER = 'testrunner.TestRunner'

Ett test

1
2
3
4
5
6
7
8
from testrunner import TestCase
from models import BlogEntry

class SimpleTest(TestCase):
    def testBlogEntry(self):
        be = BlogEntry(title = 'Hello world')
        be.save()
        self.failUnlessEqual(be.slug, 'hello-world')
blog comments powered by Disqus