2013-01-23 11 views
9

Podczas pisania testów dla mojej klasy napotkałem interesujący prosty problem. Chciałbym potwierdzić DictEqual dwa słowniki zawierające pewną listę. Ale ten list nie mogą być klasyfikowane w ten sam sposób -> co skutkuje nieudanej próbiePython unittest - potwierdzanie słownika z listami

Przykład:

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

to nie od czasu do czasu, w zależności od kolejności elementów na liście

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

Jakieś pomysły, jak to potwierdzić w prosty sposób?

Myślałem o używaniu set zamiast list lub sortowania list przed porównaniem.

+0

Jeśli masz wiele przypadków tego problemu, polecam sprawdzenie odpowiedzi [@Jon Reid] (http://stackoverflow.com/a/14493005/881224). – Droogans

Odpowiedz

7

Można spróbować PyHamcrest(przykład poprawione)

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

(pierwsza wartość 2347 faktycznie zostanie owinięty w sposób dorozumiany equal_to dopasowującego.)

+0

Początkowo byłem jak "biblioteka do luźnego zbierania kolekcji?" ... wtedy zdałem sobie sprawę, że * to * wydaje się mieć kilka zastosowań. Ładny link. – Droogans

+0

To wygląda fajnie. Podoba mi się zdanie o stylizowanych twierdzeniach testowych. Zdecydowanie skorzystam z tej platformy do testowania. Jednak w moim przypadku prawdopodobnie łatwiej jest używać zestawów zamiast list. Jeśli twierdzę, większy słownik z kilkoma listami w nim, zaczyna być dużo pisania na jedno twierdzenie. –

+0

@ sjudǝʊ Wtedy prawdopodobnie zmieniłbym test, aby użył 'has_entry' zamiast' has_entries' i przetestował każdy wpis osobno. –

0

Jak na temat korzystania all:

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

używam coś takiego z py.test, ale myślę, że to powinno działać dla ciebie.


commenter wskazał, że zamówienie zostanie wkręcić mnie tutaj --- fair enough ... Chciałbym po prostu korzystać z zestawów, a następnie.

+0

To nie działa, '' ('sąsiedzi', [1,2,3]) '' nie jest w '' [('neighbours', [1,3,2]), ...] '' ! – mouad

+0

Ahh ok. Cóż, może używać zestawów. – BenDundee

+0

Rzeczywiście. Zestawy są prawdopodobnie najprostszym rozwiązaniem. –

0

można zrobić:

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

Oczywiście, zakładając, że wszystkie wartości mogą i powinny być posortowane. Pierwsza z nich nie jest nawet prawdziwa w przypadku małego przykładu OP, a tego ostatniego należy się spodziewać IMHO - rzadko się zdarza, aby kolejność list nie miała znaczenia. – delnan

+0

Myślałem, że miał na myśli wartości zawsze będą listami. – thikonom

+0

Wartość klucza 'sąsiedzi', tak. Ale twój kod próbuje również sortować wszystkie inne wartości (w przykładzie OP, wartość klucza 'state', który jest liczbą całkowitą). – delnan

0

może możesz osobno sprawdzić te dwa elementy:

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