Ryhdyin tänään toteuttamaan unit-testausta erääseen Django-pohjaiseen web-projektiin. Ohjelmointikielenä on siis Python. Olen erittäin tyytyväinen siihen, miten kätevästi koko projektin voi testata yhdistelemällä sopivasti unittest- ja doctest-testejä.

Django tukee molempia frameworkkeja automaattisesti. Testipatteriston voi ajaa läpi yhdellä komennolla, joka näyttää onnistuessaan suunnilleen tältä:

$ ./manage.py test

…………….. Link to heading

Ran 17 tests in 2.780s

OK Destroying test database…

Aloitin testien rakentamisen luomalla joukon luokkia, jotka perivät unittest.TestCasen. Ne tyhjentävät tietokannan ja luovat sinne esimerkkidataa jokaista testiä varten. Näissä luokissa suoritetaan sellaiset laajemmat testit, jotka eivät liity pelkästään yksittäisiin funktioihin.

class SiteTestCase(TestCase):
    def setUp(self):
        cleanup()
        create_sites(self)
    def tearDown(self):
        cleanup()
    def testXxx(self):
        ...

Käytin globaaleja funktioita (cleanup, create_sites) tietokannan käsittelyyn, koska silloin niitä on kätevä hyödyntää myös doctesteissä. Doctestejä on puolestaan mukava ripotella suoraan funktioiden yhteyteen tuotantokoodiin. Ne ovat normaalikäytössä ikäänkuin kommentteja, eivätkä häiritse tuotantoa.

class Site(CompatibleModel):
    objects = CustomManager('site')
    name = SlugField(max_length=254)
    title = CharField(max_length=254)
    secret = CharField(max_length=254)
    notify_url = CharField(max_length=254)
@classmethod
def get_by_name(cls, name):
    """
    >>> from djangoapp import tests
    >>> tests.cleanup()
    >>> data = tests.create_sites()
    >>> site = Site.get_by_name('testsite1')
    >>> site.name
    u'testsite1'
    """
    return cls.objects.get(name__exact=name)</code></pre>

Ylläolevaan esimerkkiin on upotettu doctest-testi. Se siivoaa ensin tietokannan, luo esimerkkidatan, ja varmistaa sitten, että esimerkkidata löytyy tietokannasta kyseisellä funktiolla. Doctestin syntaksi on sama kuin interaktiivisessa Python-tulkissa. Tässä viimeinen rivi kertoo, mitä aiemman rivin pitää tulostaa, jotta testi menee läpi. Vastaavia ehtoja voi olla useita.

Doctestien selkeänä etuna on se, että ohjelmoija näkee koko ajan koodista, onko kaikkiin funktioihin liitetty tarvittavat testitapaukset. Niiden ohella voi vielä käyttää python-coverage -työkalua. Se mittaa testien ajamisen yhteydessä, montako prosenttia koodin kokonaismäärästä käytiin läpi.