Direkt zum Inhalt | Direkt zur Navigation

Benutzerspezifische Werkzeuge
Anmelden
Sektionen
Sie sind hier: Startseite Dienstleistungen Schulungen Testen Unit Tests schreiben

Unit Tests schreiben

Einrichten der Testumgebung

Statt der bereits angelegten Datei src/vs.policy/vs/policy/tests.py erstellen wir ein eigenes tests-Modul:

$ rm -rf src/vs.policy/vs/policy/tests.py
$ mkdir src/vs.policy/vs/policy/tests
$ touch src/vs.policy/vs/policy/tests/__init__.py

Anschließend definieren wir im neu erstellten tests-Ordner zunächst ein Test-Fixture, eine gleichbleibende Testumgebung mit der Basisklasse VsPolicyTestCase. Hierzu erstellen wir im tests-Verzeichnis die Datei base.py mit folgendem Inhalt:

from Products.Five import zcml
from Products.Five import fiveconfigure

from Testing import ZopeTestCase as ztc

from Products.PloneTestCase import PloneTestCase as ptc
from Products.PloneTestCase.layer import onsetup

@onsetup
def setup_vs_policy():

    fiveconfigure.debug_mode = True
    import vs.policy
    zcml.load_config('configure.zcml', vs.policy)
    fiveconfigure.debug_mode = False

    ztc.installPackage('vs.policy')

setup_vs_policy()
ptc.setupPloneSite(products=['vs.policy'])

class VsPolicyTestCase(ptc.PloneTestCase):
    """This base class is used for all tests in this package.
    Utility or setup code can be added if necessary.
    """

Der @onsetup-Decorator sorgt dafür, dass zunächst vs.policy importiert und erst dann eine Plone-Site mit vs.policy aufgesetzt wird. Darüberhinaus wird die configure.zcml-Datei auch dann registriert, wenn kein entsprechender zcml-slug für die Site vorhanden ist.

VsPolicyTestCase ist die Basisklasse für alle Tests in diesem Paket. Bei Bedarf kann hier weiterer Code für das Setup oder Hilfsmethoden eingefügt werden.

Anmerkung: ZopeTestCase konfiguriert Zope, jedoch ohne automatisch die Produkte mitzuinstallieren. Dies kann explizit angegeben werden, z.B. mit:

ztc.installProduct('EasyNewsletter')

installProduct ist ein verzögerter Aufruf, der nicht innerhalb von setup_registration aufgerufen werden kann, da er dort zu spät ausgeführt wird. Daher sollte installProduct außerhalb der setup_registration-Funktion angegeben werden. Dieses Problem tritt auf, seitdem mit Plone 4 das five-Package nicht mehr im Products-Namensraum ist.

Eine vollständige Basisklasse finden Sie im EasyNewsletter: base.py.

Unit Tests schreiben

Die eigentlichen Unit-Tests werden in der Datei test_setup.py definiert und zu einer Testsuite zusammengestellt:

import unittest
from vs.policy.tests.base import VsPolicyTestCase

from Products.CMFCore.utils import getToolByName

class TestSetup(VsPolicyTestCase):

    def test_portal_title(self):
        self.assertEquals("Veit Schiele", self.portal.getProperty('title'))

    def test_portal_description(self):
        self.assertEquals("Welcome to Veit Schiele", self.portal.getProperty('description'))

def test_suite():
    suite = unittest.TestSuite()
    suite.addTest(unittest.makeSuite(TestSetup))
    return suite

Unit Tests, die auf dem Python unittest-Modul, ZopeTestCase und PloneTestCase basieren, müssen sich an einige Namenskonventionen halten:

  • Alle Testdateien müssen mit test beginnen, z.B. test_setup.py.
  • In den Testdateien werden Klassen für Testfälle definiert, die ein oder mehrere Testmethoden enthalten können, die ebenfalls mit test beginnen müssen, z.B. test_portal_title.
  • Zunächst wird die Basisklasse importiert, dann die Klassen für die Testfälle und schließlich die Test Suite selbst definiert.
  • Jede Testsuite kann aus mehreren Testklassen bestehen. Wird die Testsuite ausgeführt, werden alle Testmethoden aller Testklassen der Test-Suite ausgeführt.
  • Innerhalb einer Testklasse kann die afterSetUp()-Methode unmittelbar vor jedem Test aufgerufen werden um Testdaten für diesen Test anzugeben. Nachdem der Test durchgeführt wurde, werden die Transaktionen zurückgenommen, so dass normalerweise keine Artefakte zurückbleiben.
  • Werden jedoch Änderungen außerhalb von Zope vorgenommen, müssen diese mit der Methode beforeTearDown() aufgeräumt werden.
  • Die in einer Testklasse verwendeten Methoden wie self.assertEqual() oder self.failUnless() sind Assertion-Methoden, und wenn eine von ihnen fehlschlägt, gilt der ganze Test als fehlgeschlagen.

Assertion und Hilfsmethoden

Assertion-Methoden überprüfen, ob etwas wahr oder falsch ist. Daher kann aus den Tests auch herausgelesen werden, wie sich Ihr Produkt verhalten soll, welche Fähigkeiten es enthält. Die Liste der Assertion-Methoden ist ausführlich in der Python-Dokumentation für unittest.TestCaseObjects enthalten. Die häufigsten sind:

failUnless(expr)
stellt sicher, dass der Ausdruck expr wahr ist.
assertEqual(expr1, expr2)
stellt sicher,dass expr1 gleich expr2 ist.
assertRaises(exception, callable, ...)

stellt sicher, dass beim Aufruf von callable die Fehlermeldung exception ausgegeben wird.

Hinweis: callable sollte der Name einer Methode oder ein aufrufbares Objekt sein, nicht ein aktueller Aufruf, z.B.:

self.assertRaises(AttributeError, myObject.myMethod, someParameter)
fail()
Dies ist sinnvoll, wenn ein Test noch nicht fertiggestellt ist oder in einem if-Statement, das deutlich macht, dass der Test fehlgeschlagen ist.

ZopeTestCase und PloneTestCase fügen zu den Assertion-Methoden noch weitere hilfreiche Methoden und Variablen hinzu, die mit Zope interagieren. Hier nur kurz die wesentlichen Variablen:

self.portal
Die PloneSite, in der der Test ausgeführt wird.
self.folder
Der member-Ordner des Mitglieds, als der die Tests ausgeführt werden.

Und hier die wesentlichen Methoden:

self.logout()
abmelden, d.i. die Rolle anonymous bekommen;
self.login()
sich erneut anmelden; wird ein Nutzername mit übergeben, erfolgt die Anmeldung als dieser Nutzer.
self.setRoles(roles)

durchläuft eine Liste von Rollen, die angenommen werden sollen.

self.setRoles((Manager,)) lässt Sie beispielsweise die Rolle des Managers für eine bestimmte Zeit annehmen.

self.setPermissions(permissions)
analog können auch Berechtigungen für den Testnutzer in self.folder angegeben werden;
self.setGroups(groups)
eine Liste von Gruppen, der der aktuelle Nutzer angehören soll.

Mehr über Unit Tests in Python erfahren Sie in der unittest-Python-Dokumentation.

Tipps & Tricks

  • Übernehmen Sie Tests z.B. aus Plone wenn diese Ihren eigenen Absichten entsprechen.

  • Dummy-Implementierungen sind häufig der einzige Weg um bestimmte Funktionen zu testen. Siehe auch CMFPlone/tests/dummy.py für einige Dummy-Objekt-Beispiele.

  • Tests können auch verwendet werden um Dinge auszuprobieren – sie sind eine sichere Umgebung.

  • Während des Debugging können print-Statements in den Test eingefügt werden um nachvollziehbare Hinweise im Terminal zu erhalten.

  • Es kann jedoch auch gleich der Python-Debugger in die Testmethoden importiert werden mit:

    import pdb; pdb.set_trace()
    

    Anschließend können Sie mit r schrittweise durch den Testkode gehen.

    Mehr zum Python-Debugger erfahren Sie in Debugging und in der Python-Dokumentation.