-
Notifications
You must be signed in to change notification settings - Fork 90
Tests
Um sicherzustellen, dass Funktionen innerhalb von SmartHomeNG während der Weiterentwicklung und evtl. Umstrukturierungen weiterhin funnktionieren, werden sogenannte Unittests geschrieben. Diese sind, ebenfalls wie alles andere in SmartHomeNG, in Python programmiert.
Bei der Weiterentwicklung von SmartHomeNG sollten die Tests nach jeder Änderung ausgeführt. Dadurch kann sichergestellt werden, dass bestehende Funktionalität weiterhin fehlerfrei funktioniert und eventuelle Fehler frühzeitig erkannt werden.
Die Ausführung der Tests basiert auf zwei Technologien:
-
pytest
- Framework für die Testausführung -
tox
- Utility für unterschiedliche Testsläufe
Die Tests werden mittels pytest
(siehe Doku) ausgeführt. Dies ist ein Framework mit dem Tests strukturiert abgelegt und in unterschiedliche Dateien verteilt werden koennen. Das Framework bietet weiterhin Funktionen an mit denen diverse Testszenarien geprüft werden können (Assertions).
Das Utility tox
wird verwendet um pytest
auszuführen. Es unterstützt allerdings auch noch weitere Features: so kann z.B. ein sogenannter Build erzeugt werden in dem unterschiedliche "Environments" konfiguriert werden die unterschiedliche Aufgaben erledigen können. Ausserdem kann eingestellt werden, wie die Test-Discovery durchgeführt werden soll und für welche Python Versionen Tests ausgeführt werden sollen.
Damit ist es möglich die Ausführung so zu gestalten, dass einerseits eine Umgebung für die direkte Ausführung der Tests vorhanden ist, andererseits auch eine Umgebung für einen Syntax-Check (flake) oder sogar eine Umgebung um einen Dokumentationsbuild zu starten.
Bei SmartHomeNG wird allerdings nur die Ausführung der Tests sowie (bei bedarf, und daher auskommentiert in der Konfiguration) des Syntax-Checks (flake).
Möchte man die Tests nach einer Weiterentwicklung ausführen, so muss der Befehl tox
ausgeführt werden. Damit wird das Utility tox
gestartet, welches standardmäßig pytest
ausführt.
Ein Testlauf sieht so aus:
$ tox
[...]
============================= test session starts ==============================
platform linux -- Python 3.3.6, pytest-2.9.2, py-1.5.2, pluggy-0.3.1 -- /home/travis/build/smarthomeNG/smarthome/.tox/py33/bin/python3.3
cachedir: .cache
rootdir: /home/travis/build/smarthomeNG/smarthome, inifile: tox.ini
plugins: cov-2.5.1, timeout-1.2.1, betamax-0.5.1
timeout: 30.0s method: signal
collected 219 items
tests/test_config.py::TestConfigConf::test_confread_ignores_empty_name PASSED
tests/test_config.py::TestConfigConf::test_confread_lists_spaces PASSED
tests/test_config.py::TestConfigConf::test_confread_multiline PASSED
[...]
plugins/database/tests/test_single.py::TestDatabaseSingle::test_single_returns_last_value_outside_range PASSED
plugins/database/tests/test_single.py::TestDatabaseSingle::test_single_sum PASSED
==================== 218 passed, 1 skipped in 21.50 seconds ====================
___________________________________ summary ____________________________________
py33: commands succeeded
congratulations :)
Diese Ausführung verwenden den aktuell ausgecheckten Quellcode und Branch. D.h. befindet man sich aktuell in develop
Branch, so werden die Tests darin ausgeführt.
Die Konfiguration wird in der Datei tox.ini
:
- Sektion
pytest
legt allgemeine Einstellungen fuerpytest
fest: Pfade oder Namenschema für Test-Dateien, Test-Funktionen und Test-Klassen - Sektion
testenv
legt eine auszuführende Testumgebung fest: Umgebungsvariablen,pytest
-Kommando, notwendige Dependencies
SmartHomeNG besteht aus zwei Bereichen: Code und Plugins. Für beide Bereiche gibt es bzw. kann es Tests geben, die getrennt voneinander abgelegt werden.
Die Tests für den SmartHomeNG Core liegen direkt im Hauptverzeichnis im Verzeichnis tests
. Das Verzeichnis hat folgende Struktur:
-
mock
- Verzeichnis in dem Teile des Core als Mocks (keine reale Implementierung von Klassen, sondern nur leere Hülsen) -
resources
- Verzeichnis in denen Dateien abgelegt werden die für die Ausfürhung von Tests notwendig sind (z.B. eigeneitems.yaml
). -
test_XXXX.py
- Dateien in denen Tests für XXX implementiert sind (z.B.test_config.py
)
Wenn Teile des Cores getestet werden sollen, empfiehlt es sich diese in einer entsprechenden Datei abzulegen. So sind Tests fuer das einlesen der Konfiguraton (Implementierung in lib/config.py
) in einer Datei mit dem Namen test_config.py
abgelegt. Oder Tests für Funktionen aus lib/utils.py
liegen demnach in test_util.py
.
Bei der Ausfürhung der Tests werden dort alle Tests berücksichtig, die im tests/
Verzeichnis liegen und dem Namensschema test_XXX.py
entsprechen. Die eigentlichen Testfunktionen muessen dem Schema test_XXX()
entsprechen.
Beispiel:
import unittest
class ExampleTests:
def test_XXX(self):
# execute some code, an verify results
self.assertEqual(1, ...)
self.assertFalse('123' in ...)
Genauso wie es sich auch für Core Tests verhält, verhält es sich auch bei den Plugin-Tests. Diese Tests werden in das Plugin-Verzeichnis in tests
abgelegt. Sobald auch hier Tests vorhanden sind, werden diese automatisch ausgeführt. Auch die Namenskonvention ist identisch (Dateien nach dem Schema test_XXX.py
, Funktionen nach dem Schnema test_XXX()
) und die Verzeichnisstruktur sollte beibehalten werden (mock
, resources
- falls notwendig).
Werden die Tests für Plugins umfangreicher, empfiehlt es sich diese in separate Dateien aufzuteilen um den Überblick zu vereinfachen. Gleicher Code kann auch in eine eigene Datei oder Module ausgelagert und in den jeweiligen Testdateien eingebunden werden.
Damit die Tests automatisch bei jeder Änderung des Codes ausgeführt werden, ohne dass dies manuell angestoßen werden muss, wird Travis-CI verwendet. Dort sind beide Bereiche von SmartHomeNG eingebunden um die Tests automatisiert auszuführen:
- Core: https://travis-ci.org/smarthomeNG/smarthome/
- Plugins: https://travis-ci.org/smarthomeNG/plugins/
Damit Travis-CI weiss, was zur Ausführung der Tests ausgeführt werden soll, gibt es in jedem Repository eine Konfigurationsdatei mit dem Namen .travis.yml
. Dort ist beispielsweise hinterlegt, dass die Tests mit tox
ausgeführt werden sollen, dass sie mit bestimmten Python Versionen ausgeführt werden sollen, oder dass es sich um ein Python-Projekt handelt (Travis-CI kann prinzipiell alle Arten von Projekten und Programmiersprachen unterstützen).
Einstellungen in .travis.yml
(und deren Wert):
-
language
- legt die Programmiersprache fest (python
) -
python
- enthät eine Liste von Python-Versionen die ausgeführt werden sollen (Liste mit3.3
bis3.5
) -
before_install
- konfiguriert ein oder mehrere Befehle die vorinstall
ausgeführt werden (git
Kommando um Submodule zu initialisieren) -
install
- konfiguriert ein oder mehrere Befehle die vor der eigentlichen Ausführung ausgeführt werden (pip
Kommando um Requirements zu installieren,tox-travis
,virtualenv
) -
script
- definiert das eigentlich auszuführende Skript (Ausführung vontox)
Travis-CI für damit die Tests für alle angegebenen Python-Versionen aus. Durch die Angabe von mehreren Python-Versionen wird eine Ausführungsmatrix bei Travis-CI erzeugt, die alle Versionen beinhalten. Eine solche Ausführungsmatrix kann auch durch andere Parameter (wie z.B. Definition von Umgebungsvariablen) erzeugt werden.
Die Ausführung der Tests läuft in alle Repositories gleich ab und verwendet die gleiche Konfiguration und das gleiche Skript (jeweils dupliziert in den Repositories und sollten gleich gehalten werden). Der einzige Unterschied ist der Wert REPOSITORY_ORIGIN
in der .travis.yml
, wechler den Name des Repositories behinhaltet für das die Konfiguration gilt.
Werden nun Änderungen in die Repositories gepusht wird ein Build-Job in Travis-CI angestoßen (funktionert mit einem GitHub-Hook). Travis-CI führt den Build anhand der Konfiguration aus, in der letzendlich die Ausführung des Skriptes .travis.sh
steht.
Folgende Schritte werden ausgeführt (laut Konfiguration .travis.yml
):
- Travis-CI checkt standardmäßig das Repository in der Revision des letzten Commits aus
- Anschließend werden die Requirements installieren (z.B.
tox
) - Danach wird das Skript
.travis.sh
ausgeführt
Die Ausführung des Skriptes ist wie folgt (in .travis.sh
):
- Ermitteln in welchem Branch die Repositories ausgecheckt werden sollen (
master
vs.develop
) - Auschecken der Repositories, sofern sie noch nicht von Travis-CIS ausgecheckt wurden
- Einrichten der Umgebung, sodass die Checkouts verwendet werden (z.B.
plugins
Repo incore
verlinken) - Starten der Test-Suite mit
tox
Es wird die folgende Verzeichnisstruktur auf Travis-CI hergestellt:
/home/travis/build/smarthomeNG - Standardverzeichnis von Travis
/plugins - Checkout des plugins-Repo
/smarthome - Checkout des smarthome-Repo
Zu 1) Wird ein Build in einem Branch angestoßen so wird der entsprechende Name des Branch in der Umgebungsvariable TRAVIS_BRANCH
gesetzt. Diese Variable wird verwendet um zu pruefen ob der master
oder develop
der fehlenden Repositories ausgecheckt werden soll.
Zu 2) Travis-CI checkt standardmäßig das Repository aus, für den der Build angestoßen wurde. Ergaben sich Änderung im core
Repository, wird dieses ausgecheckt, ergaben sich Änderungen im plugins
Repository, wird das ausgecheckt. Je nach dem fehlt dann das plugins
oder das core
Repository, welches dann per Skript noch zusätzlich ausgecheckt im zuvor ermittelten Branch wird.
Zu 3) Sind alle Repositories ausgecheckt, werden entsprechende Links gesetzt, damit das ausgecheckte plugins
Repository unterhalb des ausgecheckten core
Repository zu finden ist.
Zu 4) Ist die Umgebung mit den jeweilgen Repositories eingerichtet, kann der Testlauf gestartet werden.
Die aktuellen Release Notes und die Release Notes der zurückliegenden Versionen sind in der Dokumentation im Abschnitt Release Notes zu finden.