Le migliori pratiche per evitare i rami parziali

3

Realizzo molta codifica in python e ho ottenuto molte condizioni di if senza un'istruzione else per dire rami parziali.

per esempio:.

# if a certain kwarg was passed to a function call
if kwargs.get('a_option'):
    # overwrite an entry in an already existing dict:
    config['a_option'] = kwargs['a_option']

Questo appare sempre nella copertura del mio test come hit parziale a meno che non lo contrassegnassi con pragma: no branch .

Quindi la mia domanda è, è considerato una cattiva pratica usare i rami parziali? E se lo è, ci sono modi popolari per evitarli? (non qualcosa come "aggiungi altro senza istruzioni come in python else: pass ")

Si noti che questo si riferisce alla ramificazione in generale e non solo a Python. L'ho usato solo come esempio, ma mi interessa in generale come queste cose vengano gestite indipendentemente dalla lingua.

    
posta Igle 16.02.2018 - 15:56
fonte

3 risposte

5

Devi distinguere tra copertura della linea e copertura della filiale. La copertura della linea misura la percentuale di linee che sono state eseguite, la copertura delle filiali la percentuale di rami che sono stati presi. Un if ha sempre due rami (per True e False), indipendentemente dalla presenza o assenza di un blocco else .

Diamo un'occhiata a questo codice semplificato:

def under_test(cond):
  foo()
  if cond:
    bar()
  baz()

Se eseguiamo under_test(True) otteniamo la copertura della linea completa, poiché verrà eseguito tutto il codice foo(); bar(); baz() . Ma if ha ancora una copertura parziale, perché non abbiamo preso entrambi i rami: non è mai stato falso. Abbiamo bisogno di un altro test case under_test(False) che esegua foo(); baz() per ottenere una copertura completa delle filiali.

I report sulla copertura delle filiali possono guidarti verso i casi di test che hai mancato (una metodologia di test white-box). Se un test non viene mai eseguito, questo suggerisce tre possibili azioni:

  • Potresti determinare che questo comportamento non è necessario, quindi rimuovi il condizionale. Se segui TDD, questo condizionale non dovrebbe mai essere stato scritto perché non ha un test.
  • Il comportamento è importante, quindi aggiungi un caso di test per esercitare questo ramo.
  • Il comportamento non è molto importante, quindi annoti la linea per escluderla dalla copertura. Questo è sensato per il debug di codice come assert False che non dovrebbe mai essere raggiunto.
risposta data 16.02.2018 - 18:18
fonte
1

Il tuo codice deve avere una logica corretta. Cioè, una funzione dovrebbe calcolare un valore, visualizzare qualcosa, ecc. In conformità con il suo contratto. Se ciò significa usare if senza else , così sia. Alcuni rami di codice possono essere davvero difficili o impossibili da coprire con test di unità automatizzati, e va bene.

Avere una copertura di prova del 100% è un obiettivo lodevole, ma impossibile. Coprire quanto più codice possibile nel test, lasciare il resto per il test manuale. Ricorda, il tuo codice deve essere corretto e test che dimostrino che è un mezzo per raggiungere un fine: consegnare il software con il minor numero possibile di bug. Il controllo della casella "Copertura del codice 100%" in alcuni elenchi di controllo non è l'obiettivo finale.

Un'opzione che potresti considerare è il refactoring, ma solo se questa è una quantità non banale di codice:

someFunction() {
  if (a) {
    foo(bar);
  }
}

foo(bar) {
  // Do a bunch of stuff
}

Ora puoi coprire gli interni di if nel loro metodo, senza dover impostare la condizione a nel primo metodo, operazione che potrebbe essere difficile da eseguire correttamente. Ancora una volta, non prendere questo come un consiglio generale per prendere il coraggio di qualsiasi condizionale e dividerlo in una nuova funzione: questo ha senso a volte, altre volte, non così tanto. Non esiste " best practice " (questo termine mi fa rabbrividire di più quando ottengo). Hai semplicemente bisogno di sviluppare un occhio su come refactoring code in modo che il tuo team ritenga sia leggibile e facilmente manutenibile .

    
risposta data 16.02.2018 - 16:42
fonte
-4

Come si può vedere in questo esempio, la regola di non usare un se senza un altro porta spesso a un design del software migliore.

Sì, è una cattiva pratica usare i rami parziali.

L'unico modo per evitarli è pensare troppo al caso contrario. Per favore, chiediti cosa dovrebbe accadere, quando nell'altro caso. Non c'è davvero bisogno di una gestione speciale dell'altro caso? C'è un modo (come nell'esempio) per ottimizzare il codice sorgente?

    
risposta data 16.02.2018 - 16:24
fonte

Leggi altre domande sui tag