2013-01-23 3 views
9

Mentre scrivevo alcuni test per la mia classe, ho riscontrato un problema semplice e interessante. Vorrei assegnare a DictEqual due dizionari contenenti una lista. Ma questo liste non possono essere ordinati in uno stesso modo -> che si traduce in test fallitoPython unittest - Asserting dictionary with lists

Esempio:

def test_myobject_export_into_dictionary(self): 
    obj = MyObject() 
    resulting_dictionary = { 
      'state': 2347, 
      'neighbours': [1,2,3] 
     } 
    self.assertDictEqual(resulting_dictionary, obj.exportToDict()) 

questa strategia dovesse fallire di volta in volta, a seconda ordine degli elementi in lista

FAIL: test_myobject_export_into_dictionary 
------------------------------------ 
- 'neighbours': [1,2,3], 
+ 'neighbours': [1,3,2], 

Qualche idea su come affermarlo in modo semplice?

Stavo pensando di utilizzare set anziché list o gli elenchi di ordinamento prima del confronto.

+0

Se si verificano molti casi di questo problema, si consiglia di controllare la risposta [@Jon Reid] (http://stackoverflow.com/a/14493005/881224). – Droogans

risposta

7

si potrebbe provare PyHamcrest(Esempio corretto)

assert_that(obj.exportToDict(), has_entries(
            { 'state': 2347, 
             'neighbours': contains_inanyorder(1,2,3) })) 

(Il primo valore 2347 in realtà viene avvolto in un implicito equal_to matcher.)

+0

All'inizio ero come "una biblioteca per la raccolta differenziata che corrisponde?" ... poi mi sono reso conto che * sembra * avere pochi usi. Bel collegamento – Droogans

+0

Questo sembra fantastico. Mi piacciono le affermazioni testate stilizzate di questa frase. Userò sicuramente questo framework per i test. Tuttavia, nel mio caso, è probabilmente più semplice usare set anziché elenchi. Se sto affermando un dizionario più grande con diverse liste, inizia a scrivere molto per una affermazione. –

+0

@ sjudǝʊ Quindi probabilmente altererei il test per usare 'has_entry' invece di' has_entries' e testare ogni voce separatamente. –

0

Come sull'utilizzo all:

assert all((k,v) in resulting_dictionary.iteritems() 
      for (k,v) in obj.exportToDict().iteritems()) 

Io uso qualcosa di simile con py.test, ma penso che dovrebbe funzionare per voi.


Un commentatore ha sottolineato che l'ordine mi vite qui --- abbastanza giusto ... mi basta usare set, poi.

+0

Questo non funziona, '' ('neighbors', [1,2,3]) '' non è in '' [('neighbors', [1,3,2]), ...] '' ! – mouad

+0

Ahh ok. Bene, allora può usare i set. – BenDundee

+0

Infatti. Gli insiemi sono probabilmente la soluzione più semplice. –

0

Si può fare:

a = {i:sorted(j) if isinstance(j, list) else j for i,j in resulting_dictionary.iteritems()} 
b = {i:sorted(j) if isinstance(j, list) else j for i,j in obj.exportToDict().iteritems()} 
self.assertDictEqual(a, b) 
+0

Ovviamente, presuppone che tutti i valori possano e debbano essere ordinati. Il primo non è nemmeno vero nel piccolo esempio di OP, e il secondo è da aspettarsi IMHO - è raro che l'ordine delle liste non abbia importanza. – delnan

+0

ho pensato che intendesse che i valori saranno sempre liste. – thikonom

+0

Il valore per la chiave 'neighbours', sì. Ma il tuo codice tenta di ordinare anche tutti gli altri valori (nell'esempio OP, il valore per la chiave 'state', che è un numero intero). – delnan

0

forse puoi controllare separatamente i due elementi:

obj_dict = obj.exportToDict() 
    self.assertEqual(resulting_dictionary['state'], obj_dict['state']) 
    self.assertCountEqual(resulting_dictionary['neighbours'], obj_dict['neighbours'])