Come si strutturano i casi di test su oggetti con più gradi di libertà?

3

Sto testando un metodo parametrizzato da due input e dipende da una strategia. Ecco cosa ho:

[TestCase(input_a1, input_b1, strategy1)]
[TestCase(input_a2, input_b1, strategy1)]
[TestCase(input_a3, input_b1, strategy1)]
[TestCase(input_a1, input_b2, strategy1)]
[TestCase(input_a2, input_b2, strategy1)]
[TestCase(input_a3, input_b2, strategy1)]

[TestCase(input_a1, input_b1, strategy2)]
[TestCase(input_a2, input_b1, strategy2)]
[TestCase(input_a3, input_b1, strategy2)]
[TestCase(input_a1, input_b2, strategy2)]
[TestCase(input_a2, input_b2, strategy2)]
[TestCase(input_a3, input_b2, strategy2)]

Il mio metodo di prova assomiglia a questo:

[TestCase(expected, input_a3, input_b2, strategy2)]
void TestMethod(Output expected, Input a, Input b, Strategy strategy)
{
    var TestObject = new TestObject(strategy);
    var actual = testObject.TestMethod(a, b);
    // Assert expected == actual
}

Non è difficile immaginare come sono arrivato qui. Ho iniziato variando input_a e mantenendo input_b e strategy1 costante, terminando con 3 casi di test.

[TestCase(input_a1, input_b1, strategy1)]
[TestCase(input_a2, input_b1, strategy1)]
[TestCase(input_a3, input_b1, strategy1)]

Poi ho copiato quei casi di test e ho variato input_b con le altre due costanti, moltiplicando i miei casi di test.

[TestCase(input_a1, input_b2, strategy1)]
[TestCase(input_a2, input_b2, strategy1)]
[TestCase(input_a3, input_b2, strategy1)]

Poi ho variato il strategy , moltiplicando di nuovo i miei casi di test.

[TestCase(input_a1, input_b1, strategy2)]
[TestCase(input_a2, input_b1, strategy2)]
[TestCase(input_a3, input_b1, strategy2)]
[TestCase(input_a1, input_b2, strategy2)]
[TestCase(input_a2, input_b2, strategy2)]
[TestCase(input_a3, input_b2, strategy2)]

Ritengo che i miei casi di test stiano crescendo ad un ritmo allarmante. Ora ho bisogno di aggiungere un terzo Strategy . Se continuo così, aggiungerei un'altra serie di casi di test. Se aggiungessi un altro input, input_c , moltiplicherei i miei set di test case almeno di 2.

È troppo prolisso per testare ogni combinazione di input_a , input_b e strategy ?

    
posta Giuliano Conte 27.02.2018 - 05:03
fonte

3 risposte

6

Puoi utilizzare l'opzione combinatoria di NUnit come questa

void TestMethod(
    [Values(input_a1, input_a2, input_a3)]Input a,
    [Values(input_b1, input_b2)]          Input b,
    [Values(strategy1, strategy2)]        Strategy strategy)
{
    var TestObject = new TestObject(strategy);
    var actual = testObject.TestMethod(a, b);
    // Assert
}

Ciò si tradurrà in 3 * 2 * 2 = 12 casi di test totali, che sono cross-join di tutti i valori dati.

Per quanto riguarda il numero in rapida crescita di test. Mentre penso che odori, non è un grosso problema. Fintanto che tutti i test sono eseguiti velocemente, non ci sono problemi a generare migliaia di casi di test.

    
risposta data 27.02.2018 - 07:12
fonte
1

In primo luogo, questo è lo scenario esatto per cui molte persone usano lo scripting. Nel mio caso particolare, di solito uso gli script Tcl per generare test unitari per il codice C, ma il principio si applica in generale. Una volta installato uno script adatto, aggiungere ulteriori parametri per generare ulteriori test per una determinata funzione è un esercizio banale. Funzionalmente, questo è esattamente la stessa cosa dell'utilizzo di una definizione di test case parametrizzata dal framework di test dell'unità scelto, quindi se il framework fornisce quell'abilità, utilizzarla con tutti i mezzi.

In secondo luogo, per una funzione che ha diversi parametri, ti consigliamo di esaminare la struttura di test dell'unità per assicurarti di toccare il caso normale e qualsiasi edge o casi speciali, ma , solo tu è necessario toccare il caso normale una volta. Ho visto molti test unitari in cui l'autore ha fornito diversi valori dal normale intervallo di valori (da uno a un test), ritenendo che in qualche modo aumentassero l'efficacia del test.

Se questa linea di ragionamento è vera, allora il set perfetto di unit test per una funzione che prende un intero con 32 bit con segno dovrebbe avere ~ 2 miliardi di variazioni. Chiaramente, non è questo il caso. Perversamente, devi stare attento a questo ancora più attentamente quando stai usando gli script per generare le funzioni di test, perché è così facile da fare. Quando decidi quali valori passare ai tuoi test unitari, ricorda "Prova ciò che devi, ma solo quello che devi".

In terzo luogo, per le combinazioni di parametri, si applicano le stesse considerazioni. Con l'aumentare del numero di parametri di una funzione, il numero di test unitari per tale funzione aumenterà inevitabilmente . Sì, sarà lungo (e noioso se devi scriverli tutti a mano). Ciò non significa che non dovresti avere quei test; significa solo che dovresti scaricare tutto il tedio sul computer, se possibile.

    
risposta data 27.02.2018 - 16:50
fonte
0

Dato che vuoi tutte le combinazioni, perché non generare i casi di test in modo programmatico?

generateTestCases()
{
    a_inputs = {input_a1, input_a2, input_a3};
    b_inputs = {input_b1, input_b2, input_b3};
    strategies = {strategy1, strategy2, strategy3};

    foreach(a_input in a_inputs)
    {
        foreach(b_input in b_inputs)
        {
            foreach(strategy in strategies)
            {
                // create/run test case on a_input, b_input, strategy
            }
        }
    }
}

Questo eseguirà ogni combinazione di input e strategie. L'aggiunta di più input o strategie richiede solo la modifica di una riga. Questa funzione può generare l'elenco di TestCase s che vengono poi letti dai metodi di test, oppure i metodi di test possono essere eseguiti dall'interno del ciclo più interno sopra, a seconda di quale sia il migliore per il tuo codice base.

    
risposta data 27.02.2018 - 07:04
fonte

Leggi altre domande sui tag