Come gestire correttamente i parametri globali per il test delle unità in python?

10

Stiamo implementando molti algoritmi che in genere hanno molti parametri condivisi, noti pubblicamente e rilevanti per la sicurezza.

Attualmente, usiamo semplicemente una classe che contiene tutti i parametri e due oggetti globali predefiniti:

class PublicParams(object):
    p = q = 0

    def __init__(self, p, q):
        self.p = p
        self.q = q

# used for tests
publicParams_test = PublicParams(15,7)               

# Some 2048 bit numbers for example
publicParams_secure = PublicParams(128378947298374928374,128378947298374928374)  

Gli algoritmi prendono quindi un oggetto PublicParams come argomento che assume come valore predefinito publicParams_secure produttivo

def AlgoOne(n, publicParams = publicParams_secure):
    # do stuff with publicParams.p
    # ...
    AlgoTwo(x, publicParams)

e

def AlgoTwo(x, publicParams= publicParams_secure):
    # do stuff with publicParams.q

In questo modo possiamo ancora iniettare diversi parametri pubblici per semplificare i test unitari:

class AlgoOneTest(unittest.TestCase):
    def test(self):
        # compare with manually computed result
        self.assertTrue(AlgoOne(1, publicParams_test) == 10) 

Ciò che non mi piace di questo approccio:

  • Assegnare il publicParams a un valore predefinito lo rende facoltativo quando si chiama un algoritmo. Tuttavia, diventa facile dimenticare di passarlo quando si chiama AlgoTwo da AlgoOne , il che comporterebbe l'utilizzo di due oggetti diversi se l'oggetto test è stato passato a AlgoOne

C'è un modo migliore che è meno incline ma offre comunque flessibilità per il test delle unità? È davvero una buona pratica?

    
posta netik 13.03.2017 - 22:20
fonte

3 risposte

1

Crea file di configurazione test_config.py e production_config.py . Selezionane uno usando la variabile d'ambiente o un argomento da riga di comando. Importa (o leggi / analizza, se scegli .json / .txt invece di .py ) e rendi il risultato disponibile all'intero programma attraverso un oggetto globale in un modulo che puoi importare ovunque.

Questo è molto simile a quello che stai già facendo, eccetto che lo fa un passo in più, dall'ambito globale verso la shell da cui invochi python. Il vantaggio è che non c'è più il rischio di confondere accidentalmente la produzione e la configurazione di test: non è possibile leggere entrambi i file nella stessa sessione python, poiché c'è solo una variabile d'ambiente / riga di comando.

    
risposta data 15.04.2017 - 12:00
fonte
0

Ci sono un certo numero di cose che puoi fare.

  • Interrompi l'uso di globals
  • Interrompi l'utilizzo dei valori predefiniti
  • Verifica sempre tramite i metodi di supporto privati che non consentono l'uso dei valori predefiniti

    def _AlgoOne(n, publicParams):
        return AlgoOne(n, publicParams)
    

Sicuramente una di queste opzioni richiede molto lavoro, ma non ti chiederei se questo non fosse un problema per te.

    
risposta data 15.03.2017 - 03:15
fonte
0

Si potrebbe sempre separare la raccolta di valori dal contesto globale e l'elaborazione di quei parametri.

def do_the_thing():
    """Provides the public (rather untestable) context.
    _do_the_thing(global1, global2, publicParams)"""

def _do_the_thing(blah, blah, blah):
    "Actually does the thing"
    pass
    
risposta data 15.03.2017 - 03:55
fonte

Leggi altre domande sui tag