2013-03-21 6 views
27

Sto scrivendo un doctest per una funzione che genera un dizionario. Il doctest sembraCome posso testare l'uguaglianza dei dizionari con il pacchetto doctest di Python?

>>> my_function() 
{'this': 'is', 'a': 'dictionary'} 

quando l'eseguo, non riesce con

Expected: 
    {'this': 'is', 'a': 'dictionary'} 
Got: 
    {'a': 'dictionary', 'this': 'is'} 

La mia ipotesi migliore per quanto riguarda la causa di questo fallimento è che doctest non sta controllando l'uguaglianza dizionario, ma __repr__ uguaglianza. This post indica che esiste un modo per ingannare doctest nel controllo dell'uguaglianza dei dizionari. Come posso fare questo?

+0

dal dict è ordinata, non è possibile utilizzare la dict così com'è. devi trasformarlo in un oggetto ordinato – ornoone

+0

Le risposte elencate di seguito sono tutte nella documentazione doctest: http://docs.python.org/2/library/doctest.html#warnings –

+0

@ornoone Ma perché? Sono oggetti uguali, ecco cosa dovrebbe controllare il doctest. – endolith

risposta

19

doctest non controlla __repr__ uguaglianza, di per sé, è solo controlla che l'uscita è esattamente lo stesso. Devi assicurarti che tutto ciò che è stampato sia lo stesso per lo stesso dizionario. È possibile farlo con questo one-liner:

>>> sorted(my_function().items()) 
[('a', 'dictionary'), ('this', 'is')] 

Anche se questa variazione sul tuo soluzione potrebbe essere più pulita:

>>> my_function() == {'this': 'is', 'a': 'dictionary'} 
True 
+2

La tua soluzione è più pulita ma non riuscirà a dirti a cosa è effettivamente valutata my_function. – jQwierdy

+0

la soluzione di pprint sembra molto più pulita, vedi la risposta di charlax –

+1

ma cosa succede se si tratta di un esempio di documentazione e voglio mostrare un input realistico e un output realistico? C'è un modo per farlo controllare l'uguaglianza invece delle stringhe esatte? – endolith

2

trasformarlo in un elenco tramite dict.items() e poi ordinarlo ...

>>> l = my_function().items() 
>>> l.sort() 
>>> l 
[('a', 'dictionary'), ('this', 'is')] 
+0

o come one-liner: 'ordinato (my_function(). Items())' – hardmooth

12

ho finito per usare questo. Hacky, ma funziona.

>>> p = my_function() 
>>> {'this': 'is', 'a': 'dictionary'} == p 
True 
+3

Non penso che sia un hacky (anche se scriverei 'p == {etc}') - questa è la prima tecnica consigliata nella relativa sezione di [i documenti] (http://docs.python.org/3/library/doctest.html # avvisi). – DSM

+5

perché non 'my_function() == {'this': 'is', 'a': 'dictionary'}'? – endolith

+0

Lo svantaggio qui è una volta che l'asserzione fallisce, non si conoscono le chiavi, i valori sono errati. La soluzione con 'pprint' mostrerebbe una differenza utile. – geekQ

34

Un altro buon modo è quello di utilizzare pprint (nella libreria standard).

>>> import pprint 
>>> pprint.pprint({"second": 1, "first": 0}) 
{'first': 0, 'second': 1} 

Secondo il suo codice sorgente, è l'ordinamento dicts per voi:

http://hg.python.org/cpython/file/2.7/Lib/pprint.py#l158

items = _sorted(object.items()) 
+4

sarebbe bello, ma python devs [non consiglio questo] (https://bugs.python.org/issue20310) perché non garantiscono la stabilità dei pprint tra le versioni. – max

+0

inoltre, questa soluzione funziona necessariamente per altri tipi di dati (come set). – hardmooth

+0

Il vantaggio qui è una volta che l'asserzione fallisce, 'pprint' mostrerà una diff helful. Se l'implementazione di 'pprint' cambia tra la versione di Python, beh, abbiamo bisogno di aggiustare i nostri test o semplicemente duplicare l'implementazione nel nostro codice per mantenerlo stabile. – geekQ

1

È possibile creare un'istanza di unittest.TestCase classe all'interno del vostro doctests, e usarlo per confrontare dizionari:

def my_function(x): 
    """ 
    >>> from unittest import TestCase 
    >>> t = TestCase() 

    >>> t.assertDictEqual(
    ...  my_function('a'), 
    ...  {'this': 'is', 'a': 'dictionary'} 
    ...) 

    >>> t.assertDictEqual(
    ...  my_function('b'), 
    ...  {'this': 'is', 'b': 'dictionary'} 
    ...) 

    """ 
    return {'this': 'is', x: 'dictionary'} 

Nota: questo approccio è migliore piuttosto che controllare se i dizionari sono uguali, perché mostrerà diff tra i due dizionari.

Problemi correlati