unittesting: assertEqual meldet Fehler wo keiner ist - oder?

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.
Antworten
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

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
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

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
[code]#!/usr/bin/env python
import this[/code]
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

Naja, es täte auch ein Methode __cmp__ , die regelt genauso Vergleiche...
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

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
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

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
[code]#!/usr/bin/env python
import this[/code]
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

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 :oops: ...)

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
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

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
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

Hi Christian!
CM hat geschrieben: aber mir gefällt es so
Mir auch, besonders der Smilie mitten im Code :D

Gruß, mawe
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Oh, die Zeile, die Du meinst, mawe ist etwas verunglückt. Habe die Smilies nicht aktiviert. Sie sollte eigentlich so aussehen:

Code: Alles auswählen

j = DNA(s[x+i:x+i+minimum])
Ist wohl auch etwas sinnvoller ...

Gruß,
Christian
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

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 :oops: ...
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

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? :wink:

Gruß,
Christian

PS Meinte im vorigen post natürlich, daß ich vergessen habe die Smilies zu INaktivieren.
Milan
User
Beiträge: 1078
Registriert: Mittwoch 16. Oktober 2002, 20:52

CM hat geschrieben:

Code: Alles auswählen

AssertionError: ATGCATGCATGCTGAATGCATGCATGCTTGT != ATGCATGCATGCTGAATGCATGCATGCTTGT
Ich versteh aber net, wo dass hier herkmmt :oops: ...
mawe
Python-Forum Veteran
Beiträge: 1209
Registriert: Montag 29. September 2003, 17:18
Wohnort: Purkersdorf (bei Wien [Austria])

Hi!

@CM: Jetzt poste (bitte) endlich den gesamten Code, sonst nimmt die Raterei und Verwirrtseinheit (cooles Wort) kein Ende :D

Gruß, mawe
Dookie
Python-Forum Veteran
Beiträge: 2010
Registriert: Freitag 11. Oktober 2002, 18:00
Wohnort: Salzburg
Kontaktdaten:

Milan hat geschrieben:
CM hat geschrieben:

Code: Alles auswählen

AssertionError: ATGCATGCATGCTGAATGCATGCATGCTTGT != ATGCATGCATGCTGAATGCATGCATGCTTGT
Ich versteh aber net, wo dass hier herkmmt :oops: ...
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
[code]#!/usr/bin/env python
import this[/code]
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

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
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Arrgh! Jetzt hatte ich den BBCode deaktiviert. Shiet!

natürlich: http://www.amp.ucdavis.edu/Homepages/St ... hon/DNA.py
Antworten