Qual è il modo più conciso per testare una condizione booleana con molte clausole AND?

4

Ho una funzione che restituisce la disponibilità di un modulo, in cui il modulo è disponibile solo se sono soddisfatte più condizioni. Il codice ha il seguente aspetto:

bool isShipAvailable() {
  bool isAvailable;

  isAvailable = this->areSystemsCalibrated;
  isAvailable = isAvailable && this->areEnginesFunctional;
  isAvailable = isAvailable && this->isWarpDriveOnline;
  isAvailable = isAvailable && this->isFluxCapacitorOnline;
  isAvailable = isAvailable && this->areStabilizersOnline;

  return isAvailable;
}

Sto provando a testare questo codice senza creare qualcosa di grande o difficile da mantenere. So che potrei scrivere test per tutte le permutazioni, ma sarebbe accettabile testare il caso in cui tutte le condizioni sono true e quindi testare ogni scenario in cui solo una condizione è false ? Farebbe troppe ipotesi sull'implementazione nei test?

Modifica: non mi sto chiedendo come rifattorizzare la logica booleana per essere concisi, ma piuttosto quale sarebbe il modo più breve per testare ogni permutazione di quella logica. I dettagli dell'implementazione stessa non sono molto importanti.

    
posta codehearts 31.05.2018 - 20:06
fonte

4 risposte

10

Il test unitario riguarda il comportamento del codice sotto test dal punto di vista dei suoi clienti. Pertanto, poiché la tua classe di test è uno dei suoi clienti, dovresti definire quali sono le tue aspettative.

Ci sono alcune aspettative che vedo dalla tua implementazione:

  1. Dato che i sistemi sono calibrati, i motori sono funzionali, il disco di curvatura è online, il condensatore di flusso è online e gli stabilizzatori sono online, quindi la nave è disponibile. 1
  2. Dato che i sistemi non sono calibrati, la nave non è disponibile.
  3. Dato che i motori non sono funzionanti, la nave non è disponibile.
  4. E così via.

Pertanto, mi aspetterei 6 test, in quanto ci sono 6 comportamenti distinti a cui mi prendo cura come cliente.

Would that be making too many assumptions about the implementation in the tests?

Abbastanza divertente, perché in realtà credo che sia vero il contrario: stai facendo troppe ipotesi sulla tua implementazione quando collaudi tutte le combinazioni. Ricorda che provi sempre dal punto di vista dei tuoi clienti. Se provi ogni singola combinazione, allora stai dicendo che i tuoi clienti si preoccupano di tutte quelle combinazioni. La mia comprensione del codice è che non importa quale combinazione di sistemi sia offline o non funzionale. Finché un sottosistema non è in linea, la nave non è disponibile, punto. Pertanto, lo testerei come tale.

1. Phew, potrebbe richiedere un po 'di setup per testare questa affermazione. Se questo è il tuo sentimento, allora forse i tuoi test ti stanno parlando: il tuo codice sotto test sta facendo parecchio.

    
risposta data 31.05.2018 - 20:46
fonte
4

La libreria standard fornisce una funzione specifica ed esplicita per attività come questa. Lo userei semplicemente, e vedo poco motivo per testare che faccia è un lavoro.

#include <algorithm>

class foo {
    bool areSystemsCalibrated,
        areEnginesFunctional,
        isWarpDriveOnline,
        isFluxCapcacitorOnline,
        areStabilizersOnline;

    bool foo::*conditions[5] = {
        &foo::areSystemsCalibrated,
        &foo::areEnginesFunctional,
        &foo::isWarpDriveOnline,
        &foo::isFluxCapcacitorOnline,
        &foo::areStabilizersOnline
    };

public:
    bool isShipAvailable() const {
        return std::all_of(std::begin(conditions), std::end(conditions),
            [&](bool foo::*b) { return this->*b; });
    }
};

Se, a quel punto, vuoi veramente testarlo comunque, hai una serie di condizioni. Ciò rende relativamente semplice testare qualsiasi combinazione di condizioni che ritieni opportune - fino a includere un test esaustivo di ogni combinazione possibile, se proprio vuoi.

    
risposta data 31.05.2018 - 21:21
fonte
2

Con un numero ampio ma limitato di casi di test Test basati sui dati è la risposta.

... testing done using a table of conditions directly as test inputs and verifiable outputs as well as the process where test environment settings and control are not hard-coded. In the simplest form the tester supplies the inputs from a row in the table and expects the outputs which occur in the same row. The table typically contains values which correspond to boundary or partition input spaces.

Hai bisogno di 1 test esplicito in cui tutte le condizioni sono vere dicendo "funziona".

Utilizzando un test guidato dai dati, puoi testare tutti i valori "falsi" parametrizzando ogni campo booleano come input per il test.

Il modo in cui lo fai dipende dallo stack tecnologico e dal framework di test unitario, ma potrebbe essere ridotto a un metodo di test e a un loop che itera sugli input previsti (esempio in C #, framework MS Test):

[TestClass]
public class ShipTests
{
    [TestMethod]
    public void ItWorks()
    {
        var ship = new SpaceShip(true, true, true, true, true);

        Assert.IsTrue(ship.isShipAvailable());
    }

    [TestMethod]
    public void ItDoesntWork()
    {
        var inputs = new bool[][]
        {
            { false, true, true, true, true },
            { false, false, true, true, true },
            // ...
            { false, false, false, false, false },
        };

        foreach (var row in inputs)
        {
            var ship = new SpaceShip(row[0], row[1], row[2], row[3], row[4]);

            Assert.IsFalse(ship.isShipAvailable());
        }
    }
}

Robert Harvey ha commentato la domanda:

That said, if you really want tests for this, I think one test with all flags true and one test with one of the flags false really ought to suffice.

Non è sufficiente, poiché ogni flag falso fa sì che la nave non sia disponibile. Non si desidera verificare che l'unità di curvatura non sia disponibile e che tutti i test vengano superati se un difetto causa la disattivazione imprevista del condensatore di flusso.

Il condensatore di flusso è importante, lo sai. Molto importante. Deve essere online indipendentemente da cosa - anche più di Facebook!

Otherwise, there's 5 flags here; a fully comprehensive test would require 32 test permutations.

Sì, ci sono un gran numero di casi di test, ma il lavoro richiesto per mantenere quei test è minimo se si utilizza un test guidato dai dati. E se questa è tutta la manipolazione dei dati in memoria, il tempo di esecuzione del test è trascurabile. Penso di aver dedicato più tempo a scrivere questa risposta rispetto a tutti gli sviluppatori del team che trascorreranno questi test nel corso della vita del progetto.

    
risposta data 31.05.2018 - 21:56
fonte
-1

would it be acceptable to test the case where all conditions are true and then test each scenario where only one condition is false?

Sì.

Ma dovresti testarlo in base al tuo caso d'uso, ad esempio fino a quando le tue condizioni variano in modo indipendente.

    
risposta data 31.05.2018 - 20:29
fonte

Leggi altre domande sui tag