Come gestire correttamente i parametri globali per i test unitari in Python?


11

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

Attualmente, utilizziamo 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 quindi prendono un PublicParamsoggetto come argomento che per impostazione predefinita è produttivopublicParams_secure

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 un più semplice test dell'unità:

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

Cosa non mi piace di questo approccio:

  • Dare publicParamsun valore predefinito lo rende facoltativo quando si chiama un algoritmo. Tuttavia, diventa facile dimenticare di averlo passato quando si chiama AlgoTwodall'interno AlgoOne, il che comporterebbe l'utilizzo di due oggetti diversi se l'oggetto test fosse passato aAlgoOne

Esiste un modo migliore che è meno incline ma offre comunque flessibilità per i test unitari? È davvero questa la migliore pratica?

Risposte:


1

Creare file di configurazione test_config.pye production_config.py. Selezionane uno usando la variabile di ambiente o un argomento della riga di comando. Importalo (o leggi / analizza, se scegli .json/ .txtinvece 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, tranne per il fatto che va oltre, dall'ambito globale alla shell da cui invochi Python. Il vantaggio è che non c'è più il rischio di confondere accidentalmente produzione e configurazione di test: non è possibile leggere entrambi i file nella stessa sessione di Python, poiché esiste solo una variabile di ambiente / riga di comando.


0

Ci sono molte cose che puoi fare.

  • Smetti di usare i globi
  • Smetti di usare i valori predefiniti
  • Testare sempre con metodi di supporto privati ​​che non consentono l'uso delle impostazioni predefinite

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

Sicuramente una di queste opzioni richiede molto lavoro, ma non ti chiederesti se questo non è stato un problema per te.


0

Si potrebbe sempre separare la raccolta di valori dal contesto globale e l'elaborazione di tali 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.