Automatisierte Tests für Odoo-Anpassungen
Kurz gesagt
Eigenen Odoo-Code sichern Sie mit Unit-Tests im Ordner tests/ Ihres Moduls ab; Odoo führt sie beim Installieren oder Aktualisieren mit --test-enable aus. Bei eigener Installation starten Sie den Lauf selbst und binden ihn in eine Continuous Integration ein, auf Odoo.sh übernimmt das der Entwicklungszweig. Auf Odoo Online sind eigene Module nicht möglich, dort bleibt das Nachstellen in einer Testkopie.
Das Wichtigste
- Python-Testdateien liegen im Ordner tests/ des Moduls und beginnen mit test_; JavaScript-Tests unter static/tests/.
- Ohne eigenes Tag trägt eine Testklasse standard und post_install (Community-Zweig 20.0).
- Getestet werden nur Module, die der Lauf installiert oder aktualisiert: beim ersten Mal mit -i, nach einer Codeänderung mit -u; ein bereits installiertes Abhängigkeitsmodul wird nur mitgeprüft, wenn es in -i oder -u mitgenannt wird.
- Odoo.sh führt die Testsuite im Entwicklungszweig aus, Produktion und Staging führen keine Unit-Tests aus.
- Browsertests laufen laut Dokumentation in Chrome im Headless-Modus; schlägt ein solcher Test fehl, legt Odoo einen Screenshot ab.
- assertQueryCount() begrenzt im Test die Zahl der SQL-Abfragen eines Vorgangs.
Eigener Code in Odoo ändert Abläufe, die der Standard nicht kennt: eine zusätzliche Rabattregel, ein eigenes Feld in der Buchhaltung, eine umgebaute Ansicht. Ein manueller Test beantwortet nur, ob die Änderung jetzt trägt; nach dem nächsten Modulupdate oder Versionssprung steht die Frage wieder offen. Ein Testlauf im Modul beantwortet sie bei jeder Änderung erneut, ohne dass jemand die Klickwege wiederholt.
Worauf es ankommt
Odoo 20.0 kennt drei Testarten: Python-Tests für die Geschäftslogik, JavaScript-Tests für das Frontend und Touren, die den Weg durch die Oberfläche nachspielen und dabei beide Seiten zusammen prüfen (Odoo-Dokumentation 20.0, Seite Testing Odoo, gelesen am 14. Oktober 2026).
Alle drei liegen im Modul: Python-Tests im Ordner tests/ neben models/ und views/, JavaScript-Tests unter static/tests/. Eine Testdatei beginnt mit test_ und wird in tests/init.py importiert; Odoo prüft nur die dort importierten Testmodule (Dokumentation Testing Odoo).
Ausgeführt werden Tests nur in installierten Modulen, und geprüft werden nur die Module, die dieser Lauf installiert oder aktualisiert. Beim ersten Lauf installieren Sie das Modul mit -i, nach einer Codeänderung aktualisieren Sie es mit -u; ein bereits installiertes Abhängigkeitsmodul wird nur mitgetestet, wenn Sie es in -i oder -u mitnennen (Tutorial Safeguard your code with unit tests, Abschnitt Running Tests). –test-enable schaltet die Ausführung ein; –test-tags tut dasselbe und wählt zusätzlich aus, was läuft, etwa –test-tags /ihr_modul für ein Modul oder –test-tags ‘/sale,-slow’ für alles aus einem Modul außer den mit slow markierten Tests.
Ohne eigenes Tag trägt eine Testklasse standard und post_install (Zweig 20.0 des öffentlichen Community-Codes, Datei odoo/tests/common.py); die Dokumentationsseite Testing Odoo nennt an dieser Stelle at_install. Der dynamische Tag entscheidet, wann der Test läuft: at_install direkt nach der Installation des Moduls, post_install nach der Installation aller Module. Das Tutorial rät, at_install nur zu setzen, wenn die Installation eines anderen Moduls das geprüfte Verhalten ändern kann; sonst verkürzt post_install den Lauf. Kommt at_install zum Einsatz, empfiehlt die Dokumentation einen Kommentar im Code, der erklärt, warum der Test vor anderen Modulen laufen muss.
Welche Testart welche Aufgabe übernimmt
Die Tabelle ordnet jeder Testart ihre Prüfaufgabe zu; die dritte Spalte nennt Datei und Aufruf. Zwei Zeilen sind keine eigene Testart: Die Query-Zählung ist eine Aussage in einem Python-Test, die Upgrade-Prüfung läuft auf einer Kopie der Datenbank.
| Testart | Was sie prüft | Datei und Aufruf in Odoo 20.0 |
|---|---|---|
| Python-Test (TransactionCase) | Rechenwege, Feldwerte, Zustandswechsel und erwartete Fehler einer Methode | tests/test_*.py; im Test assertRecordValues und assertRaises(UserError) |
| Formulartest (odoo.tests.Form) | was die Formularansicht auslöst: Standardwerte, onchange, Pflichtfelder | tests/test_*.py; im Test Form(self.env[‘modell’]) öffnen und speichern |
| HTTP-Test und Tour (HttpCase, start_tour) | Zusammenwirken von Python und JavaScript, Klicks, Dialoge, Berichte | tests/test_*.py mit self.start_tour(“/web”, “tourname”, login=“admin”); Chrome im Headless-Modus |
| JavaScript-Test (HOOT) | Frontend-Logik und Komponenten ohne Server | static/tests/*.test.js, eingetragen im Bundle web.assets_unit_tests |
| Query-Zählung (assertQueryCount) | ob ein Vorgang mehr Datenbankabfragen auslöst als erlaubt | im Python-Test; die Obergrenze steht als Zahl im Aufruf |
| Upgrade-Prüfung | Installierbarkeit auf der Zielversion und Datenmigration | leere Zielversion installieren, Kopie aktualisieren; Upgrade-Skripte liegen unter migrations/ oder upgrades/ im Modul |
Die JavaScript-Tests starten Sie im laufenden System über den Entwicklermodus: Im Menü Fehlerbeseitigungstools (englisch Debug tools) liegt der Eintrag Unit-Tests ausführen (englisch Run Unit Tests); den Weg in den Modus beschreibt Entwicklermodus in Odoo. Ein Test gehört in das Modul, in dem die Funktion entsteht; er darf nicht von Funktionen abhängen, die aus Modulen stammen, die Ihr Modul nicht als Abhängigkeit führt (Tutorial Safeguard your code with unit tests).
Teststrategie nach Risiko
Nicht jede Anpassung verdient dieselbe Prüftiefe. Die Zuordnung in dieser Tabelle ist unsere Priorisierung (redaktionelle Einschätzung); die Prüfmittel sind die in der Dokumentation 20.0 beschriebenen. Arbeiten Sie von oben nach unten.
| Risiko | Prüfmittel in Odoo 20.0 | Was der Test dafür braucht |
|---|---|---|
| Falscher Betrag, falsche Menge oder falscher Status in einem Beleg | Python-Test auf die Methode, Feldwerte mit assertRecordValues prüfen | Datensätze im setUpClass anlegen, die Aktion aufrufen, Sollwerte in einer Liste vergleichen |
| Standardablauf oder Abhängigkeit gebrochen | Standardtests der Abhängigkeit im selben Lauf ausführen: die benötigten Module mit in -u aufnehmen, etwa odoo-bin -u ihr_modul,sale –test-enable, und die Auswahl bei Bedarf mit –test-tags /ihr_modul,/sale eingrenzen; ein bereits installiertes Abhängigkeitsmodul wird ohne eigenen Eintrag in -i oder -u nicht mitgetestet | Modul und Abhängigkeitsmodul in diesem Lauf installiert oder aktualisiert; ein durchgefallener Standardtest zeigt, ob Ihre Anpassung einen Ablauf übersehen hat |
| Zugriffsrecht zu weit oder zu eng | Test mit den niedrigsten Rechten und erwartetem AccessError | Testbenutzer über new_test_user oder den users-Dekorator anlegen |
| onchange, Standardwert oder Pflichtfeld greift nicht | Formulartest mit odoo.tests.Form | Ansicht laden: reines Zuweisen von Feldern in Python löst keinen onchange aus |
| Klickweg, Dialog oder Bericht bricht in der Oberfläche | Tour über start_tour im HttpCase | Chrome im Headless-Modus; der letzte Schritt der Tour bringt die Seite in einen stabilen Zustand |
| Frontend-Komponente (OWL) bricht | JavaScript-Test mit HOOT unter static/tests | Datei endet auf .test.js und steht im Bundle web.assets_unit_tests |
| Datenverlust beim Versionssprung | Modul auf einer leeren Zielversion installieren und die Daten in einer Kopie aktualisieren | Upgrade-Skripte für umbenannte Felder, Modelle und externe Bezeichner; sie laufen nur beim Aktualisieren des Moduls |
| Performance-Rückschritt durch zusätzliche Abfragen | assertQueryCount im Python-Test | Obergrenze als Zahl im Test festhalten |
| Konfiguration ohne Testcode: Studio-Anpassung, Berichtslayout, E-Mail-Vorlage | Handprüfung in einer Testkopie, auf Odoo.sh von der Rolle Tester | Prüfplan mit Klickweg und Sollwert je Anpassung |
Wo die Tests laufen
Bei eigener Installation starten Sie den Lauf auf der Kommandozeile gegen eine Testkopie; für den Dauerbetrieb empfiehlt das Tutorial ausdrücklich eine eigene Continuous Integration.
Auf Odoo.sh führt der Entwicklungszweig die Testsuite bei jedem Push aus und lädt dafür Demo-Daten; Produktions- und Staging-Datenbanken führen keine Unit-Tests aus, weil dort keine Demo-Daten liegen und ein Lauf die Ausfallzeit verlängern würde (Odoo.sh, Seite Branches, Abschnitte Production und Staging). In den Einstellungen des Zweigs legen Sie fest, welche Test-Tags laufen und ob die Suite überhaupt läuft; die Option, nur die Module des Zweigs zu installieren, ist die Voreinstellung. Für die Handprüfung gibt es die Rolle Tester: Sie erreicht Staging- und Entwicklungsdatenbanken, aber nicht die Produktion.
Auf Odoo Online sind eigene Module und Module aus dem Apps Store nicht möglich (Odoo-Dokumentation 20.0, Seite Odoo Online). Dort läuft für eigenen Code kein automatischer Test; Sie stellen Konfiguration in einer Testkopie nach. Wie Sie eine solche Kopie je Hostingmodell anlegen und was darin abgeschaltet sein muss, steht in Testumgebung für Odoo.
So sieht das im Alltag aus
Beispielrechnung mit erfundenen Zahlen. Ihr Modul enthält 40 Tests und braucht im Entwicklungszweig drei Minuten je Lauf. Bei zwölf Commits in der Woche sind das 36 Minuten Rechenzeit. Für die Installation aller Standardmodule mit eingeschalteter Suite nennt die Odoo.sh-Dokumentation bis zu eine Stunde je Lauf — bei zwölf Commits bis zu zwölf Stunden. Deshalb bleibt die Voreinstellung, nur die eigenen Module zu installieren, und die Suite läuft trotzdem nach jedem Commit.
Den Ausgang lesen Sie im Protokoll: In einer Datenbank des Entwicklungszweigs stehen die Testergebnisse in install.log, die Modulaktualisierungen in update.log (Odoo.sh, Seite Branches, Abschnitt Logs).
Typische Fehler
- Testdatei ohne Import: Sie liegt in tests/, steht aber nicht in tests/init.py; Odoo führt den Test dann nicht aus.
- Klasse ohne Basisklasse: Eine einfache unittest.TestCase trägt die Standard-Tags nicht und wird vom Standardlauf übersprungen; die Dokumentation nennt das ein häufiges Problem.
- JavaScript-Datei ohne die Endung .test.js oder außerhalb des Bundles web.assets_unit_tests: Odoo behandelt die Datei dann als Produktivcode oder lädt sie nicht.
- cr.commit() im Test oder im Geschäftscode: Die Testtransaktion lässt sich nicht mehr sauber zurückrollen, Daten bleiben in der Datenbank und der nächste Lauf stolpert darüber (Odoo-Leitlinien und Tutorial).
- Nur mit Administratorrechten geprüft: Rechtefehler, die Anwender treffen, fallen im Test nicht auf; die OCA-Richtlinien raten, mit den niedrigsten Rechten zu testen.
- Test legt denselben Datensatz mehrfach an: Die OCA-Richtlinien zeigen, dass Dekoratoren wie users intern mit subtests arbeiten; Datenbanktransaktion und Cache werden zwischen den Teilläufen nicht geleert, deshalb scheitert ein zweiter Durchlauf am doppelten Login eines bereits angelegten Benutzers.
- Test hängt am Tagesdatum: Wer im Test datetime.now() oder datetime.today() auswertet, bekommt je nach Tag ein anderes Ergebnis; die OCA-Richtlinien raten zu festen Datumswerten, etwa über die Bibliothek freezegun.
- Testlauf gegen Produktivdaten: Odoo.sh führt in Produktion und Staging keine Unit-Tests aus; nutzen Sie den Entwicklungszweig oder eine Kopie.
So gehen Sie vor
Die Schritte 2 bis 4 brauchen Schreibzugriff auf das Modul und die Möglichkeit, Module zu aktualisieren; auf Odoo.sh genügt die Rolle Entwickler mit einem Push in den Entwicklungszweig.
- Prüfziel wählen: Suchen Sie die Zeile Ihrer Anpassung in der Risikotabelle. Ergebnis: ein Prüfziel statt eines Vorsatzes.
- Testordner anlegen: tests/init.py und tests/test_thema.py, Import in der init.py. Ergebnis: Die Datei wird beim Lauf berücksichtigt.
- Test schreiben und zuerst fehlschlagen lassen: Das Tutorial verlangt, dass ein Test zu einer Fehlerbehebung ohne die Korrektur durchfällt.
- Einzeln starten: odoo-bin -u ihr_modul –test-enable –test-tags /ihr_modul. Ergebnis: eine Zeile je Test mit ok oder der Traceback.
- Tag bewusst setzen: bei post_install bleiben, außer die Installation eines anderen Moduls kann das geprüfte Verhalten ändern; at_install braucht dann einen Kommentar im Code.
- Lauf automatisieren: auf Odoo.sh über die Einstellung des Zweigs (Test-Tags, Suite ein oder aus), bei eigener Installation über einen CI-Dienst Ihrer Wahl. Ergebnis: Der Lauf startet ohne Sie.
- Vor dem Versionssprung wiederholen: Modul auf einer leeren Zielversion installieren, Daten in einer Kopie aktualisieren, Tests und Upgrade-Skripte laufen lassen. Ergebnis: Ein Datenverlust fällt vor dem Produktiv-Upgrade auf.