Unittests: PDF Handout - Berthold Höllmann: Vorträge bei der

Werbung
Unittests in Python
Authors:
Date:
Version:
Berthold Höllmann
2009-09-06 13:33:01 +0200 (So, 06 Sep 2009)
23
Inhalt
1 Einleitung
2
2 Talk Format
2
3 Linus’ Law
2
4 Warum also testen?
2
5 Testmethoden
2
6 xUnit Paradigma
3
7 unittest
3
8 unittest: Einfaches Beispiel aus der Python Dokumentation
3
9 unittest: Mehr Details
3
10 unittest: Mehr Details (2)
3
11 Mehr zu ”unittest“
4
12 Kritik an unittest
4
13 Andere Optionen
4
14 doctest
4
15 doctest Beispiel des vorhergehenden Tests
4
16 Noch ein Beispiel
5
17 doctest Details
5
18 doctest Details (2)
5
19 doctest Details (3)
5
20 doctest Details (4)
6
1
21 doctest Details (5)
6
22 doctest Details (6)
6
23 doctest details (7)
6
24 doctest details (8)
7
25 doctest Nutzen
7
26 Ausführbare Dokumentation
7
27 Kritik an doctest
7
28 Unklare Bereiche
8
29 Testing Links
8
30 Beispiel
8
31 Diskussion
8
1
Einleitung
Testen essentieller Bestandteil des Software Entwicklungsprozess.
2
Talk Format
• Einführung in das Testen mit Python
• Beispiel eines Test Problems
• Text nach Intro to python testing talk (unittest, doctest, coverage), Original Quellen
sind dort verlinkt.
3
Linus’ Law
given enough eyeballs, all bugs are shallow
Code Complete“ führt aus, dass umfangreiche Beta Tests die meiste Fehler (˜75%) aufdecken, durch
”
testen dagegen werden etwa 30-40% der Fehler entdeckt.
4
Warum also testen?
• Vertrauen
• Refaktorieren
• Zur Zusammenarbeit mit anderen Entwicklern
5
Testmethoden
Alle Arten, hier werden wir haupsächlich «white box» Unit Tests behandeln.
Ein Unit Test testet in der Regel genau einen Aspekt.
2
6
xUnit Paradigma
Abgeleitet von Kent Beck’s SUnit
# psuedocode
setup()
# verschiede Annahmen bezüglich des Verhaltens
teardown()
7
unittest
Ursprünglich als PyUnit entwickelt, modelliert nach JUnit (das sich an SUnit anlehnt).
Test Klassen werden von unittest.Testcase abgeleitet.
Jede Methode deren Name mit test anfängt ist ein Testcase.
8
unittest: Einfaches Beispiel aus der Python Dokumentation
import random
import unittest
class TestSequenceFunctions(unittest.TestCase):
def setUp(self):
self.seq = range(10)
def testchoice(self):
# note that method begins with "test"
element = random.choice(self.seq)
self.assert_(element in self.seq)
if __name__ == ’__main__’:
unittest.main()
9
unittest: Mehr Details
setUp() und tearDown() werden vor bzw. nach jedem Testcase ausfeführt.
setUp stellt die notwendige Umgebung für die Testfälle sicher (z.B. füllen einer Datenbank, o.Ä.).
tearDown räumt wieder auf, um den Zustand vor den Tests wieder herzustellen.
10
unittest: Mehr Details (2)
Es unittest.TestCase hat verschiedene assert* und fail* Methoden:
• assert_(expr [,msg]) - Wenn expr unwahr ist, signalisiere den Misserfolg mit msg.
Korrespondiert zu failUnless.
• assertEqual(first, second [, msg])
• assertNotEqual
• assertRaises(exception, callable, ...)
• ...
3
11
Mehr zu ”unittest“
Siehe auch:
• TestSuite: Ähnlich TestCase, definieret aber keine Tests, sondern Grupiert sie.
• TestResult: Hält die Testergebnisse der TestCase und TestSuite Instanzen.
• TestLoader: Generiert eine Folge von Tests aus Klassen und Modulen.
12
Kritik an unittest
Negativ:
• Warum sind die Klassen nach Java Klassen entworfen? (Python untypische Vererbung und
Abstraktion)
• Zu schwergewichtig, zu umfangreiche Klassen, frameworky
• Der Fokus liegt auf dem Testen, dies erschwert das aktualisieren -- warum schlägt ein Test
fehl?
Positiv:
• Ist Teil der Standard Bibliothek
• Unkompliziert
13
Andere Optionen
• Nose
• Twisted Trial
• py.test
14
doctest
Verwandelt Python Docstrings (in Modulen, Klassen, Funktionen oder Methoden) in Tests.
Ursprüngliche Motivation war es die Korrektheit von Dokumentation sicherzustellen.
Nimmt Ausschnitte aus interaktiven Sitzungen und lässt sie ablaufen.
15
doctest Beispiel des vorhergehenden Tests
"""
>>> import random
>>> seq = range(10)
>>> element = random.choice(seq)
>>> element in seq
True
"""
import doctest
doctest.testmod()
4
16
Noch ein Beispiel
import doctest
def factorial(n):
"""Return the factorial of n, an exact integer >= 0.
>>> [factorial(n) for n in range(6)] # doctest: +SKIP
[1, 1, 2, 6, 24, 120]
>>> factorial(-1) # doctest: +SKIP
Traceback (most recent call last):
...
ValueError: n must be >= 0
"""
# actual implementation removed....
doctest.testmod()
17
doctest Details
Es folgen einige Details über das doctest
Here is some details about the doctest module. Taken from the doctest docs.
>>> # comments are ignored
>>> foo = "bar"
>>> foo #implicit print
’bar’
>>> if foo == "baz":
...
print "baz"
... else:
...
print foo
...
bar
18
doctest Details (2)
Wahrnung. Kann Leerzeichen nicht direkt verarbeiten, stattdessen muss <BLANKLINE> benutzt werden.
>>> print ""
<BLANKLINE>
19
doctest Details (3)
Backslashes. Raw Docstrings benutzen (dieser ist nicht raw) oder sie müssen geschützt werden.
>>> line = "foo\\n"
>>> print line
foo
<BLANKLINE>
# will throw a value error here if not escaped
5
20
doctest Details (4)
Anfangsspalte ist irrelevant
>>> 2 + 2
4
Dies ist weiter eingerückt, aber das
spielt keine Rolle
>>> 2 + 2
4
21
doctest Details (5)
Exceptions. Die erwartete Ausgabe muss mit dem Traceback Header starten.:
>>> [1, 2, 3].remove(42)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ValueError: list.remove(x): x not in list
Der Traceback Stack kann aus durch einen Platzhalter (...) ersetzt werden.:
>>> [1, 2, 3].remove(42)
Traceback (most recent call last):
...
ValueError: list.remove(x): x not in list
22
doctest Details (6)
Verschiedene Optionen und Anweisungen. Man beachte die #doctest:
>>> print range(20) #doctest: +NORMALIZE_WHITESPACE
[0,
1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>> print range(20) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
[0,
1, ...,
18,
19]
>>> (1, 2)[3] = ’moo’ #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: object doesn’t support item assignment
23
doctest details (7)
Umgang mit dict s:
>>> foo = dict(a=1, b="hello", c="bye")
>>> foo # Abhängig von der Python version schlägt dies fehl
{’a’: 1, ’c’: ’bye’, ’b’: ’hello’}
Ein Workaround ist es die Schlüssel zu sortieren:
6
>>> items = foo.items()
>>> items.sort()
>>> items
[(’a’, 1), (’b’, ’hello’), (’c’, ’bye’)]
Ich vergleiche die dict s lieber:
>>> foo == {’a’: 1, ’c’: ’bye’, ’b’: ’hello’}
True
24
doctest details (8)
Behandlung von Adressen:
>>> class C: pass
>>> c = C()
>>> c # will most likely fail #doctest: +SKIP
<__builtin__.C instance at 0xb7a210ec>
>>> c #doctest: +ELLIPSIS
<__builtin__.C instance at 0x...>
25
doctest Nutzen
Drei eindeutige Anwendungsfälle:
• Testen von Beispielen in Docstrings
• Regressionstest
• Ausführbare Dokumentation
Dies sind in Erscheinung und Nutzen sehr unterschiedliche Anwendungen.
26
Ausführbare Dokumentation
Schema Defined Buttons
---------------------Let’s now create a schema that describes ...
>>> import zope.interface #doctest: +SKIP
>>> class IButtons(zope.interface.Interface):
...
apply = button.Button(title=u’Apply’)
...
cancel = button.Button(title=u’Cancel’) #doctest: +SKIP
Gefunden bei zope (Die Notiz gehauptet 100% Abdeckung)
27
Kritik an doctest
Negativ
• Kann unübersichtlich werden (z.B. Workaround for Leerzeilen)
• Der Setup/Teardown Code kollidiert z.T. mit der Dokumentation.
7
Positiv
• Leichtgewichtig
• Einfach, keine API
• In Python enthalten
• Ausgerichtet auf Dokumentation
28
Unklare Bereiche
Wie erkenne ich die Effektivität meiner Tests?
29
Testing Links
• Python Testing Tools Taxonomy (http://pycheesecake.org)
• TIP - Testing in Python mailing list
30
Beispiel
Für ein Spalten orientiertes Ausgabeformat soll eine Funktion geschrieben werden, die auf eine Gegebene
Anzahl von Stellen Zeichenketten, Integer und Float ausgeben soll.
Bei Float soll maximale Genauigkeit erreicht werden.
31
Diskussion
???
Hamburger Python User Group • 2008/10/06
View document source. Generated on: 2009-09-28 13:15 UTC. Generated by Docutils from reStructuredText
source.
8
Herunterladen