Quando scrivo un test unitario di solito fornisco un contesto (oggetto semplice o oggetto deriso / stub) che imposto in qualche modo e quindi posso eseguire la dichiarazione di assert sul contesto:
nota: il codice è in pseudo-codice; groovy like syntax:
test myTest() {
def o = getTestContext();
o.string = "testme"
o.number = "2"
assert o.mult() == "testme testme"
}
Ma come organizzare il test quando è necessario testare un'espressione booleana complessa che richiede molti parametri?
EDIT: ho sostituito l'espressione a una riga con qualcosa di più leggibile per evitare confusione.
//this is not a real class, this is an example. Naming is bad, for conciseness sake
//the expression is coming from randomness realm, so it is probably refactorable and simplifiable, but complex real world expression still exists.
enum Type {X,Y,Z}
class C {
boolean a,b,c,d;
Type t;
boolean isEnabled(boolean anotherFlag) {
def condition1 = (a || b)
def condition2 = (c && d)
def goodType1 = t == X || t == Y
def goodType2 = anotherFlag && t == Z || t == Z && !condition1
return ( condition1 || condition2 ) && (goodType1 || goodType2)
}
}
Tutti i test per questo tipo di metodi che ho letto finora sono molto prolissi, non completi e difficili da capire.
Ed è un peccato che una linea così piccola di codice, anche se è "complessa", genera test terribili.
Ho provato a suddividere l'espressione booleana in più piccoli metodi secondari, ma a volte non è così conveniente e il conteggio delle permutazioni è ancora alto. Di solito, inoltre, spezzo l'espressione in variabili intermedie, ma questo non aiuta il mondo dei test unitari ...
Come dovrei provare qualcosa del genere per fare in modo che il codice di test corrisponda alla brevità del codice testato e alla completezza che deve affermare che il mio codice funziona come previsto?
Modifica: sulla soluzione mantenuta.
Il refactoring è davvero una strada da percorrere, ma in realtà non voglio "srotolare" tutte le combinazioni manualmente nei miei test: è prolissa, brutta e difficile da capire.
Tuttavia terrò questa risposta come passaggio obbligatorio preliminare: rompere l'espressione in parti più piccole prima di ogni altra cosa.
Una volta eseguito il refactoring e il test continua a fare test combinatori, utilizzerò la soluzione di TruthTable proposta. Creerò solo le combinazioni e non dichiarerò tutto.
Ho trovato questo interessante, ma obsoleto, articolo sulla combinazione di test in Groovy.
Lo strumento di cui hanno parlato è fuori dal radar del motore di ricerca, quindi deve essere morto!
Comunque userò lo stesso schema:
assertThat(permutations, expectations, instanceObject)
Dove
-
La permutazione
- è tutti i valori possibili da assegnare alle proprietà in una "mappa condensata": (a: [vero, falso], b: [vero, falso], ...)
- l'aspettativa è tutte le combinazioni che restituiscono un valore specifico, tutte le altre combinazioni verranno verificate rispetto a un valore predefinito.