Seite 1 von 1
unittesting: assertEqual meldet Fehler wo keiner ist - oder?
Verfasst: Montag 29. November 2004, 17:34
von CM
Hoi
wollte dieser Tage etwas in Richtung unittesting ausprobieren und habe dazu mein DNA-Modul (
http://python.sandtner.org/viewtopic.php?t=2001, ist leider veraltet, werde demnächst mal was Neues rausgeben) genommen. Was ich ausprobieren wollte klappt reibungslos. Aber dann bin ich über dies hier gestolpert:
Meine Klasse sieht so aus:
Code: Alles auswählen
class DNA:
...
def __init__(self, s, out=sys.stdout):
"""Create DNA instance initialized to string s."""
self.out = out
s="".join([x.strip() for x in s.split(' ')]) #erase whitespace
self.seq = s.upper()
check = self.check_format() #Methode zum Testen ob das Inputformat
#eingehalten wurde
if not check:
raise IOError
...
#Funktion ohne bes. Wert - nur zum Testen
def __add__(self,other):
"""concatenating DNA objects and return DNA object"""
return DNA(self.seq + other.seq)
...
Und der unittest so:
Code: Alles auswählen
import unittest
class TestDNAFunctions(unittest.TestCase):
...
def setUp(self):
self.name1 = DNA('ATGCATGCATGC')
self.name2 = DNA('TGAATGCATGCATGCTTGT')
...
def test__add__(self):
"""__add__ should concatenate DNA-objects and return them as an DNA-object"""
r = 'ATGCATGCATGCTGAATGCATGCATGCTTGT'
self.assertEqual((self.name1 + self.name2),DNA(r))
...
Dieser Test versagt:
Code: Alles auswählen
...
======================================================================
FAIL: __add__ should concatenate DNA-object and return them as an DNA-object
----------------------------------------------------------------------
Traceback (most recent call last):
File "src/DNA.py", line 840, in test__add__
self.assertEqual((self.name1 + self.name2),DNA(r))
File "/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/unittest.py", line 292, in failUnlessEqual
raise self.failureException, \
AssertionError: ATGCATGCATGCTGAATGCATGCATGCTTGT != ATGCATGCATGCTGAATGCATGCATGCTTGT
----------------------------------------------------------------------
...
Warum? Was mache ich falsch? Wo liegt mein Denkfehler, wenn ich sage, daß hier doch eigentlich alles in Ordnung ist?
Zur einfacheren Darstellung

:
1. String = ATGCATGCATGCTGAATGCATGCATGCTTGT
2. String = ATGCATGCATGCTGAATGCATGCATGCTTGT
Ist doch identisch? Und es handelt sich beide Male um Darstellungen der Klassenobjekte.
(Bei den "..." habe ich jedesmal was rausgenommen, was, wie finde, nicht wichtig für das Verständnis ist.)
Gruß,
Christian
Verfasst: Montag 29. November 2004, 17:56
von Dookie
Hi Christian,
du hast wohl keine __eq__ Methode definiert in deinem DNA-Modul?
Code: Alles auswählen
def __eq__(self, other):
return self.seq == other.seq
Gruß
Dookie
Verfasst: Montag 29. November 2004, 19:07
von Milan
Naja, es täte auch ein Methode __cmp__ , die regelt genauso Vergleiche...
Verfasst: Montag 29. November 2004, 21:06
von CM
Hm, wenn ich __eq__ so definiere wie vorgeschlagen erhalte ich (alles andere ist unverändert) folgende Fehlermeldung:
Code: Alles auswählen
======================================================================
ERROR: check_partly_palindromic should return the palindromic stretch and its position in a dict
----------------------------------------------------------------------
Traceback (most recent call last):
File "src/DNA.py", line 896, in testCheckPartlyPalindromic
self.assertEqual(DNA('aATGCATg').check_partly_palindromic(),{'ATGCAT': 2})
File "src/DNA.py", line 456, in check_partly_palindromic
if len(j) == minimum: checklist[j] = x+i+1
TypeError: unhashable instance
======================================================================
FAIL: __add__ should concatenate DNA-object and return them as an DNA-object
----------------------------------------------------------------------
Traceback (most recent call last):
File "src/DNA.py", line 840, in test__add__
self.assertEqual((self.name1 + self.name2),DNA(r))
File "/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/unittest.py", line 292, in failUnlessEqual
raise self.failureException, \
AssertionError: ATGCATGCATGCTGAATGCATGCATGCTTGT != ATGCATGCATGCTGAATGCATGCATGCTTGT
----------------------------------------------------------------------
Wenn ich mit __cmp__ arbeite kommt nur der FAIL-Teil wieder. Das hatte ich eigentlich auch schon probiert, aber dummerweise erst einmal nicht erwähnt.
checklist ist die unhashable Instanz, um die es hier geht. Es handelt sich um ein dict mit Objecten der Klasse. Wenn ich das aber ändere und stattdessen nur eine Stringrepresentation dort reinschreibe, fallen andere Teile des Codes (der eigentlich schnell und reibungslos läuft) auf die Schnauze.
Sollte man etwa vermeiden innerhalb einer Klasse Objekte der Klasse in ein dict zu schreiben?
Ich kann natürlich drum herum arbeiten: Wenn ich einen anderen unittest nehme und zum Beispiel die Stringrepresentation des Objektes nehme funktioniert der Vergleich ja. Aber das erscheint mir nicht so schön: Dann müßte ja jeder Nutzer einer Klasse sich seinen eigenen Vergleich schreiben und kann nicht sagen x == y, wenn x und y Instanzen / Objekte der Klasse sind, nicht wahr?
Eigentlich würde ich beides gerne haben: Vergleichsmethoden in der Klasse und ein dict, wie checklist, (oder ähnliche Container) mit Instanzen der Klasse innerhalb der Klasse. Hat einer von euch Vorschläge zum Design?
Vielen Dank,
Christian
Verfasst: Montag 29. November 2004, 21:38
von Dookie
Also ich hab jetzt ersmal nach lesen deines Postings nen Knoten in den Gehirnwindungen. Das muss ich mir in ruhe nochmal durchlesen und versuchen zu verstehen
Dookie
Verfasst: Dienstag 30. November 2004, 03:30
von CM
Tut mir leid, wenn ich heillos verwirrend war / bin. Was ist denn nicht verständlich? (Mal abgesehen davon, daß in meinem vorherigen Posting etliche Kommata vergessen wurden und die Grammatik überarbeitet werden könnte

...)
Na, es ist wohl am besten, wenn ich da noch ein Weilchen drüber brüte - vielleicht komme ich ja auf eine Lösung.
Gruß,
Christian
Verfasst: Dienstag 30. November 2004, 08:55
von CM
Hoi
wenn ich einfach repr(j) statt j in checklist schreibe funktioniert es. Da bin ich selber über meine Hirnwirrungen gestolpert ...
Und warum hat es vorher nicht geklappt? Weil ich nicht DNA(y).check_palindromic(), sondern nur y.check_palindromic() geschrieben habe.
Falls es interessiert (und damit man alles nachvollziehen kann), habe ich hier mal die betreffende Funktion gepostet. (Ja, geht auch viel, viel kürzer, aber mir gefällt es so

.)
Code: Alles auswählen
def check_partly_palindromic(self, minimum = 6):
...
s = self.seq
returnlist = {}
checklist = {}
for x in xrange(0,len(s)):
for i in xrange(1,len(s)+1):
j = DNA(s[x+i:x+i+minimum])
if len(j) == minimum: checklist[repr(j)] = x+i+1
#increase in even steps, otherwise the sequence is not symmetric and
#per definition not palindromic
minimum += 2
if minimum > len(s): break
for y in checklist:
#gefaellt mir nicht, weil langsam:
if DNA(y).check_palindromic(): returnlist[y] = checklist[y]
return returnlist
und der zugehörige unittest (damit man auch versteht was die Funktion machen soll) ist:
Code: Alles auswählen
#check_palindromic() ist die "Schwesterfunktion von check_partly_palindromic()
def testCheckPalindromic(self):
"""check_palindromic should return a boolean value (palindromic or not?)"""
self.assert_(DNA('ATGCAT').check_palindromic())
def testCheckPartlyPalindromic(self):
"""check_partly_palindromic should return the palindromic stretch and its position in a dict"""
self.assertEqual(DNA('aATGCATg').check_partly_palindromic(),{'ATGCAT': 2})
Na ja, ich gebe es zu: Ich habe hier unnötig verquer gedacht. Trotzdem danke fürs Zurechtstutzen und den Tipp mit __eq__ bzw. __cmp__, die ich nachzuholen hatte!
Besten Gruß,
Christian
Verfasst: Dienstag 30. November 2004, 12:19
von mawe
Hi Christian!
CM hat geschrieben:
aber mir gefällt es so
Mir auch, besonders der Smilie mitten im Code
Gruß, mawe
Verfasst: Dienstag 30. November 2004, 19:35
von CM
Oh, die Zeile, die Du meinst, mawe ist etwas verunglückt. Habe die Smilies nicht aktiviert. Sie sollte eigentlich so aussehen:
Ist wohl auch etwas sinnvoller ...
Gruß,
Christian
Verfasst: Dienstag 30. November 2004, 19:57
von Milan
Hi. Hast du zufällig sowas hier geschrieben?
Code: Alles auswählen
assert "ATGCATGCATGCTGAATGCATGCATGCTTGT" != "ATGCATGCATGCTGAATGCATGCATGCTTGT"
oder woher kommt überhaupt der assertationfehler? Wenn sowas wie oebn steht ists ja klar, dass das fehlschlägt. Aber ansonsten hab ich den Rest auch net ganz verstanden

...
Verfasst: Dienstag 30. November 2004, 20:07
von CM
Hi Milan,
nein, assert habe ich nicht benutzt. Wieso? Der unittest steht ja im ersten Post. Ich habe einfach assertEqual aus dem unittest-Modul benutzt.
Nun, die Objekte sind ja auch gleich. Dummerweise habe ich, wie ihr ja richtig bemerkt habt, keine Vergleichsmethode geschrieben. Wenn ich diese aber geschrieben habe, ist hat sich Python beschwert (siehe oben). Deshalb mein work-around.
Noch Fragen?
Gruß,
Christian
PS Meinte im vorigen post natürlich, daß ich vergessen habe die Smilies zu
INaktivieren.
Verfasst: Dienstag 30. November 2004, 20:12
von Milan
CM hat geschrieben:Code: Alles auswählen
AssertionError: ATGCATGCATGCTGAATGCATGCATGCTTGT != ATGCATGCATGCTGAATGCATGCATGCTTGT
Ich versteh aber net, wo dass hier herkmmt

...
Verfasst: Dienstag 30. November 2004, 20:49
von mawe
Hi!
@CM: Jetzt poste (bitte) endlich den gesamten Code, sonst nimmt die Raterei und Verwirrtseinheit (cooles Wort) kein Ende
Gruß, mawe
Verfasst: Dienstag 30. November 2004, 21:13
von Dookie
Milan hat geschrieben:CM hat geschrieben:Code: Alles auswählen
AssertionError: ATGCATGCATGCTGAATGCATGCATGCTTGT != ATGCATGCATGCTGAATGCATGCATGCTTGT
Ich versteh aber net, wo dass hier herkmmt

...
Hi Milan,
Das hier kommt aus dem Modul unittest. Siehe -> pydoc unittest - oder -> /usr/lib/python2.3/unittest.py - oder -> /usr/lib/python2.4/unittest.py
Gruß
Dookie
Verfasst: Dienstag 30. November 2004, 22:52
von CM
Sorry, aber ich habe wirklich nicht gedacht soviel Verwirrung stiften zu können - schließlich stand doch im ersten Post dieses "import unittest" und ihr habt so geantwortet, daß ich meinte ihr hättet verstanden. Und danach habe ich ja auch vom unittest-Modul gesprochen ...
Also, mein Code findet sich hier: [url]
http://www.amp.ucdavis.edu/Homepages/St ... hon/DNA.py[/url] aber ich habe im Code nicht aufgeräumt

.
Gruß,
Christian
Verfasst: Dienstag 30. November 2004, 22:55
von CM
Arrgh! Jetzt hatte ich den BBCode deaktiviert. Shiet!
natürlich:
http://www.amp.ucdavis.edu/Homepages/St ... hon/DNA.py