Test-Driven Development

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Beitragvon HWK » Donnerstag 11. Oktober 2007, 20:46

Joghurt hat geschrieben:Wenn du dir hingegen ein kleines Tool schreibst, dass meinetwegen bestimmte Dateien sichert, macht es Sinn, Tests zu haben, da du das Programm u.U. später mal erweitern wirst und du spätestens dann eh Test schreiben solltest.
Ja, vielleicht sollte man die Tests schreiben, wenn man ein Programm erweitert. Das scheint doch eine sinnvolle Abgrenzung zu sein, ob sich Testing lohnt.

Wo seht Ihr die Vorteile von py-test bzw. nose gegenüber unittest?

Kennt denn jemand das Buch Test Driven Development von Kent Beck?

MfG
HWK
poker
User
Beiträge: 146
Registriert: Donnerstag 20. September 2007, 21:44

Beitragvon poker » Donnerstag 11. Oktober 2007, 21:08

HWK hat geschrieben:@poker: Bedeutet das, dass durch Unittests jede Zeile des Programmcodes mindestens einmal ausgeführt werden soll? Ist das nicht ein bisschen aufwendig und in vielen Fällen auch unnötig?

Hi, das ist ne gute berechtigte Frage.

Ich sehe es so wie BlackJack und Eydu.

Der am Unit tests gekoppelte Coverage soll dir als Programmierer in erste Linie die lästige Arbeit abnehmen zu identifizieren, ob du alle benötigten Fälle (Die du für wichtig erachtest) abgedeckt hast. Bei sehr großen Anwendungen vergisst man immer wider mal für wichtige Bereiche seiner Software Unit tests zu schrieben, weil es eben Umfangreich, komplex und unübersichtlich wird[1].

Der Coverage soll dir also die Arbeit abnehmen die Bereiche zu identifizieren die noch nicht durch Unit tests angedeckt wurden[2]. Anschließend kannst du anhand des erzeugten Reports entscheiden, welche dingen deiner Meinung nach unbedingt abgedeckt werden müssen und welche für dich vernachlässigbar sind. Vernachlässigbare dingen könnten z.B. wirkliche Trivialfunktionen sein die ehe nicht mehr geändert werden und "immer" funktionieren. -- Aber wie BlackJack schon richtig angedeutet hat, der Teufel liegt im Detail ;) Oft sind es nämlich genau die dinge wo man denkt "braucht man nicht passt schon" und dort verstecken sich Fehler. Daher versuche ich meistens (je nach Komplexität der Software) eine 100%ige Abdeckung zu erreichen.

[1]: Und meistens ist es ja so das man Unit tests nicht parallel zur eigentlichen Software schreibt sondern erst viel später = Wochen oder gar Monate danach. Es sein den man nutzt Testgetriebene Entwicklung, wo erst die Unit tests geschrieben werden und dann die jeweiligen Sachen implementiert werden.

[2]: Solche bereiche sind ja nicht nur innerhalb einer Funktion, sondern stellen den ganzen Module space dar: Sprich, auch Funktionen für die überhaupt noch kein Unit test existiert, werden dir durch den Coverage angezeigt. Also z.B. wenn ich Modul ``foobar`` habe in denn ``foo`` und ``bar`` ist und ich nur einen Unit test für ``foo`` geschrieben habe, zeigt der anschließende Coverage mir an, das ``bar`` vom unit test Modul nicht ausgeführt (=getestet) wurde. :)

---


Y0Gi hat geschrieben:Achso, `py.test` nutze ich ebenfalls, da ich sehr schätze, dass es keine Vererbung voraussetzt und hübsch selbst alle Testmodule und -Callables findet. In irgendeinem Blog wurde es mit `unittest` und `nose` verglichen und `unittest` kam am besten weg

Ich schätze das war dann folgender Blog:
http://agiletesting.blogspot.com/2005/0 ... ttest.html
http://agiletesting.blogspot.com/2005/0 ... ctest.html
http://agiletesting.blogspot.com/2005/0 ... -tool.html

Y0Gi hat geschrieben:Ein paar (meinetwegen auch reallife-)Beispiele zum Testen von Datenbank- und Socket-Zugriffen würden mich brennend interessieren. Ich habe mir zwar die zahlreichen Python-Mock-Implementierungen sowie Ressourcen wie z.B. Googles Testing-Blog angesehen, aber so *richtig* komme ich da auf keinen grünen Zweig.

Die frage bei deinem Beispiel "Datenbank- und Socket-Zugriffen" ist, was genau deine Software macht? Wenn deine Software nur die Bestandteile nutzt (Die nicht von dir geschrieben sind), dann musst du die auch nicht testen! Es ist nämlich nicht deine Aufgabe auch fremde Libraries mit deinen Unit tests abzudecken. Dafür bittet es sich dann an Mocks zu schreiben.

Angenommen du hast eine Funktion oder Klasse die über `socket` auf sockets zugreift und in Abhängigkeit der Ergebnisse bestimmte Aktionen ausführt oder Zustände ändert. Jetzt kommt das Problem, das wenn du damit auf einen Externen $SERVER zugreifen der immer Bestimmte Daten zurückliefern muss. In dem Fall abstrahierst du `socket` und die erwarteten Daten von $SERVER in dem masse das deine Funktion genauso Arbeitet, als wenn du Tatsächlich `socket` mit $SERVER nutzen würdest.
Das heißt konkret, das du die erforderlichen Schnittstellen von `socket` nachschreibst die sich halt stat sich mit $SERVER verbindet, eben nur die von dir von echten $SERVER erwarteten Daten zurückliefert. Das ganze ist dann zuzusagen ein Mock - Eine Attrappe - den du deiner Funktion unterschiebst. Natürlich musst du diese Attrappe soweit nachbauen das auch die von dir erwarteten Fehler Codes/Exception wie beim Original geschmissen werden.

Und genau hier fängt es an kompliziert zu werden. Das Thema ist wirklich nicht gerade trivial, und man kann da schnell an die Grenzen des machbaren (=Verhältnismäßigkeit) kommen. Nicht um sonst kann das schreiben einer Testumgebung schnelle mal umfangreicher und komplexer werden, als die zu testenden Umgebung. Hier muss man eben von Fall zu Fall zwischen Nutzen und Verhältnismäßigkeit abwägen.

Dan sollte man noch beachten ob die Software in einer Sicherheitsrelevanten Umgebung Einsatz findet. Dort sollte, IMO, sicherheitsrelevante Bereiche garnicht mit Mocks getestet werden, sondern eine Real existierende speziell dafür geschlafene Testumgebung eingerichtet werden.
poker
User
Beiträge: 146
Registriert: Donnerstag 20. September 2007, 21:44

Unit tests als Spezifikation

Beitragvon poker » Donnerstag 11. Oktober 2007, 21:23

Was im Zusammenhang von Unit tests die 100% alles abdecken noch interessant ist, ist die Tatsache das Unit tests sozusagen auch gleichzeitig eine Spezifikation darstellen. Den sie spezifizieren (Abstrakt) ja schon die ganze Schnittstellen bis ins kleinste Detail; wenn auch nur für den Programmierer lesbar.

In dem Zusammenhang wäre es Interessant wenn es Programme geben würden, die daraus auch gleich eine Spezifikation in lesbarer Form generieren würden :D Bisher kann man sich so behelfen, in den man für Jeden Testcase docstrings schreibt die genau (Jedes Detail) beschreiben was der Testfall macht, und man ein Programm erzeugt der daraus eine Spezifikation erzeugt :D

Klingt witzig, ist aber durchaus ernst gemeint ;) Im Ruby lager gibt es durchaus (vereinzelt) schon Überlegungen in dieser Richtung. Auch gibt es da ein Unit testing Packet das nicht von Unit tests schreiben redet, sondern von Spezifikationen schreiben :D -- Ok, kann kein Schwein lesen außer die, die die "Spezifikationen" geschrieben haben oder eben die Ruby nerds :twisted:
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Beitragvon HWK » Donnerstag 11. Oktober 2007, 21:40

poker hat geschrieben:Anschließend kannst du anhand des erzeugten Reports entscheiden, welche dingen deiner Meinung nach unbedingt abgedeckt werden müssen und welche für dich vernachlässigbar sind.
Das klingt ja schon etwas realitätsnäher.
poker hat geschrieben:Ich schätze das war dann folgender Blog:
Ich hab's mir mal angeschaut. Für mich als Einzelkämpfer scheint doctest durchaus interessant zu sein. Kann noch jemand etwas zu nose sagen und natürlich zum Buch Test Driven Development von Kent Beck?
MfG
HWK
Benutzeravatar
Goswin
User
Beiträge: 361
Registriert: Freitag 8. Dezember 2006, 11:47
Wohnort: Ulm-Böfingen

Lese aufmersam alle Antworten

Beitragvon Goswin » Freitag 12. Oktober 2007, 07:30

Vielen Dank für eure Anmerkungen und Vorschläge. Ich kann mich derzeit aber noch nicht dazu äußern, weil ich bisher nur einen Teil der Python-Möglichkeiten in meinen Programmen verwendet habe und mir vieles davon noch unbekannt ist. Wenn ich Metaklassen und ähnlich Tiefschürfendes beherrsche und dabei etwas mehr Erfahrung gewinne, werde ich wahrscheinlich darauf zurückkommen wollen.
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Freitag 12. Oktober 2007, 10:49

Also Unittests würde ich auf jeden Fall vor Metaklassen reinschieben, da sie von der Komplexität wesentlich einfacher sind. Es sind normale Funktionen, die ein bestimmtes Verhalten von Code prüfen - das ist alles. Das Problem bei Unittests ist, dass es eben Arbeit ist, die nicht direkt zum Bau deines Programmes beiträgt (naja, es gibt Test-First-Programming, das ist wohl noch am motivierendsten).
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Beitragvon Y0Gi » Freitag 12. Oktober 2007, 14:02

HWK hat geschrieben:Ja, vielleicht sollte man die Tests schreiben, wenn man ein Programm erweitert.

Nein, man sollte die Tests schreiben, *bevor* man den eigentlichen Programmcode erweitert (oder überhaupt erstellt). TDD funktioniert so (bzw. so habe ich es bisher verstanden), dass man das zu lösende Problem in einem Test formuliert und dann eine Implementierung schafft oder anpasst, damit diese das Problem löst.

HWK hat geschrieben:Wo seht Ihr die Vorteile von py-test bzw. nose gegenüber unittest?

Wie ich (glaube ich) schon schrieb: `unittest` zwingt einem eine Klassenstruktur auf, die meist nur viel Ballast bedeutet. Mit `py.test` wird alles als Testcode angesehen, was sich in Modulen und Callables verbirgt, die mit dem Präfix 'test_' beginnen. Das ist für mich momentan erstmal ausschlaggebend, bis ich andere oder weitere Anforderungen habe.

HWK hat geschrieben:Kennt denn jemand das Buch Test Driven Development von Kent Beck?

Ich habe nur "Extreme Programming Planen" von Kent Beck und Martin Fowler gelesen. Naja, es war interessant, aber nur bedingt auf Hobbyprogrammierer anwendbar.

Was mir Probleme bereitet, ist, dass es gerade im Java-Bereich sehr viele Beispiele für Testing gibt, im Python-Bereich aber eher wenig (insbesondere bzgl. Stubbing und Mocking).

poker hat geschrieben:
Y0Gi hat geschrieben:Achso, `py.test` nutze ich ebenfalls, da ich sehr schätze, dass es keine Vererbung voraussetzt und hübsch selbst alle Testmodule und -Callables findet. In irgendeinem Blog wurde es mit `unittest` und `nose` verglichen und `unittest` kam am besten weg

Ich schätze das war dann folgender Blog:
http://agiletesting.blogspot.com/2005/0 ... ttest.html
http://agiletesting.blogspot.com/2005/0 ... ctest.html
http://agiletesting.blogspot.com/2005/0 ... -tool.html

Exakt, danke.
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Beitragvon Y0Gi » Freitag 12. Oktober 2007, 14:09

poker hat geschrieben:Wenn deine Software nur die Bestandteile nutzt (Die nicht von dir geschrieben sind), dann musst du die auch nicht testen! Es ist nämlich nicht deine Aufgabe auch fremde Libraries mit deinen Unit tests abzudecken.

Nein, das habe ich natürlich nicht vor. Aber ich möchte etwa prüfen, dass mein Code z.B. konkret SQLAlchemy korrekt anspricht und z.B. nur Ergebnisse mit den erwarteten Kriterien (Attribute, Anzahl, angewandte Filter) zurückliefert.

poker hat geschrieben:Dafür bittet es sich dann an Mocks zu schreiben.

Ja, da fehlt mir irgendwie der Einstieg anhand praktischer Beispiele. Insbesondere weil ich nicht weiß, auf welche Mock-Implementierung ich überhaupt aufsetzen soll.

Vorzugsweise möchte ich natürlich testen können, *ohne* eine Verbindung zu einer Datenbank oder über das Netzwerk aufbauen zu müssen; sowohl aus Zeit- als auch aus Verfügbarkeitsgründen.

poker hat geschrieben:Angenommen du hast eine Funktion oder Klasse die über `socket` auf sockets zugreift und in Abhängigkeit der Ergebnisse bestimmte Aktionen ausführt oder Zustände ändert. Jetzt kommt das Problem, das wenn du damit auf einen Externen $SERVER zugreifen der immer Bestimmte Daten zurückliefern muss. In dem Fall abstrahierst du `socket` und die erwarteten Daten von $SERVER in dem masse das deine Funktion genauso Arbeitet, als wenn du Tatsächlich `socket` mit $SERVER nutzen würdest.
Das heißt konkret, das du die erforderlichen Schnittstellen von `socket` nachschreibst die sich halt stat sich mit $SERVER verbindet, eben nur die von dir von echten $SERVER erwarteten Daten zurückliefert. Das ganze ist dann zuzusagen ein Mock - Eine Attrappe - den du deiner Funktion unterschiebst. Natürlich musst du diese Attrappe soweit nachbauen das auch die von dir erwarteten Fehler Codes/Exception wie beim Original geschmissen werden.

Ja, so stelle ich mir das auch vor. Hast du Beispielcode aus Projekten, in denen du sowas selbst mal geschrieben (oder gesehen) hast?
pug
User
Beiträge: 16
Registriert: Dienstag 4. September 2007, 17:00

Beitragvon pug » Freitag 12. Oktober 2007, 17:24

Ich bin beim Surfen auf dem agiletesting Blog über folgenden Link gestolpert.

http://pycheesecake.org/wiki/PythonTest ... stingTools

Hier werden einige Frameworks für Mock Objects aufgelistet. Ein vernünftiges Tutorial fehlt mir allerdings auch noch. Ich programmiere gerade einen Pythonwrapper für ein CLI und könnte so etwas recht gut brauchen.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Beitragvon HWK » Freitag 12. Oktober 2007, 22:41

YOGi hat geschrieben:Nein, man sollte die Tests schreiben, *bevor* man den eigentlichen Programmcode erweitert (oder überhaupt erstellt). TDD funktioniert so (bzw. so habe ich es bisher verstanden), dass man das zu lösende Problem in einem Test formuliert und dann eine Implementierung schafft oder anpasst, damit diese das Problem löst.
Das mag für einen Profi-Programmierer, der in einem Team arbeitet und die Programme weitergibt, zutreffen. Für einen Einzelkämpfer, der überwiegend Programme für sich erstellt, ist dies aber sicher überzogen. Dieser kann sicher nicht für jedes seiner Tools Unittests durchführen. Wenn überhaupt lohnt sich für ihn der Aufwand nur für Programme, die er häufig benutzt und auch verändert. Deshalb ist m.E. durchaus ein gutes Kriterium, ob sich Tests lohnen, ob ein Programm erweitert wird.
Für mich sehe ich ein weiteres Problem: Meine größeren Programme, die ich häufig und lange verwende und somit auch öfter anpasse, arbeiten meistens mit einer GUI wie wxPython oder Tkinter. Dafür Tests zu schreiben ist aber wesentlich aufwendiger, evtl. sogar mehr als den Programmcode selbst zu schreiben. Wahrscheinlich ist es hier effektiver, auf Tests zu verzichten und den Code dann anzupassen, wenn Fehler bei der Verwendung auftreten. Da die Programme ja normalerweise nicht weitergegeben werden und somit nur vom Entwickler verwendet werden, dürfte dies kein Problem darstellen. Das Testing erfolgt hier halt bei der Anwendung.
MfG
HWK
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Beitragvon Y0Gi » Samstag 13. Oktober 2007, 00:54

Klar, für jedes Hobby- oder Wegwerf-Programm mag das nicht lohnen. Wenn man allersdings eine Library erstellt, die auch mal andere verwenden könnten, sieht das schon etwas anders aus.

Ich mache auch nur vereinzelt (und gewöhnlich nachträglich) Unittests, weil das bei Webanwendungen nicht so einfach ist wie z.B. eben einer Library ohne Web-Interface oder GUI. An sich halte ich es aber für richtig und sinnvoll und bemühe ich, das weiter auszuweiten. Muss man selbst entscheiden.
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Beitragvon Y0Gi » Sonntag 14. Oktober 2007, 17:16

Ich muss mich korrigieren: `nose` ist in vieler Hinsicht `py.test` doch sehr ähnlich. Möglicherweise werde ich mich in Zukunft darauf stützen, da es z.B. auch das Coverage-Modul einbinden kann.
Benutzeravatar
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Beitragvon Joghurt » Montag 15. Oktober 2007, 00:03

HWK hat geschrieben:Das mag für einen Profi-Programmierer, der in einem Team arbeitet und die Programme weitergibt, zutreffen. Für einen Einzelkämpfer, der überwiegend Programme für sich erstellt, ist dies aber sicher überzogen. Dieser kann sicher nicht für jedes seiner Tools Unittests durchführen. Wenn überhaupt lohnt sich für ihn der Aufwand nur für Programme, die er häufig benutzt und auch verändert.
Ich würde nicht sagen, dass es überzogen ist, denn eigentlich ist es nicht so viel Mehraufwand, wie man vielleicht denkt. Schließlich testest du deinen Code nach dem schreiben ja sowieso, meistens interaktiv und schaust, ob der Code das macht, was er soll. Also könntest du eigentlich auch gleich einen Unittest schreiben und ihn dann durchlaufen lassen.
Eine andere, pythonspezifische Form wären dann die doctests, hier kannst du ja einfach deine interaktive Testsession deines Programmes copy-and-pasten und fertig ist der Unittest.

(Ich gebe gerne zu, dass ich in der Praxis auch nicht immer Unittests schreibe, aber in diesem Thread geht es ja um "best practices")
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Beitragvon HWK » Montag 15. Oktober 2007, 13:07

Das trifft sicher für reine Konsolenanwendungen zu. Es wird aber schon schwieriger, wenn es um Programme für ein lokales Netz oder gar das Internet geht. Sehr schwierig ist es aber sicher für Programme mit GUI. Das ist natürlich mit pywinauto, Ranorex und co. alles möglich, aber aufwendig. Ich habe solche Tools mehrfach verwendet, um Drittprogramme zu steuern, und das lief nie so einfach wie in den Demos.
Dass ich doctests für interessant halte, sagte ich bereits. Ich glaube aber, der Mehraufwand für unittests ist nicht mehr so groß und man hat damit wohl doch mehr Möglichkeiten.
MfG
HWK
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Beitragvon Y0Gi » Montag 15. Oktober 2007, 13:30

HWK hat geschrieben:Es wird aber schon schwieriger, wenn es um Programme für ein lokales Netz oder gar das Internet geht.

Genau da setzt Mocking an, siehe weiter oben. Dabei geht es nur darum, dass an etwas die gewünschten Aufrufe abgesetzt werden; insgeheim passiert dann aber nichts, d.h. eine tatsächliche Verbindung wird nicht aufgebaut, sondern höchstens simuliert.

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder