Come collaudi un encoder?

9

Ho qualcosa di simile a questo:

public byte[] EncodeMyObject(MyObject obj)

Sono stato test unitario in questo modo:

byte[] expectedResults = new byte[3]{ 0x01, 0x02, 0xFF };
Assert.IsEqual(expectedResults, EncodeMyObject(myObject));

EDIT: I due modi in cui ho visto la proposta sono:

1) Utilizzo di valori attesi con hardcoded, come nell'esempio sopra.

2) Utilizzo di un decodificatore per decodificare l'array di byte codificato e confrontare gli oggetti di input / output.

Il problema che vedo con il metodo 1 è che è molto fragile e richiede molti valori hard codificati.

Il problema con il metodo 2 è che il test dell'encoder dipende dal corretto funzionamento del decodificatore. Se l'encoder / decodificatore è rotto in modo uguale (nello stesso punto), i test potrebbero produrre falsi positivi.

Questi potrebbero essere gli unici modi per testare questo tipo di metodo. Se è così, allora va bene. Sto facendo la domanda per vedere se ci sono strategie migliori per questo tipo di test. Non posso rivelare gli interni del particolare codificatore su cui sto lavorando. In generale chiedo come risolvere questo tipo di problema e non ritengo che gli interni siano importanti. Supponiamo che un dato oggetto di input produca sempre lo stesso array di byte di uscita.

    
posta ConditionRacer 13.02.2013 - 19:06
fonte

6 risposte

1

Sei in una situazione un po 'odiosa lì. Se avessi un formato statico su cui stavi codificando, il tuo primo metodo sarebbe la strada da percorrere. Se fosse solo il tuo formato, e nessun altro ha dovuto decodificare il secondo metodo sarebbe la strada da percorrere. Ma non ti trovi davvero in nessuna di queste categorie.

Quello che farei è cercare di rompere le cose dal livello di astrazione.

Quindi inizierei con qualcosa a livello di bit, che testerei qualcosa come

bitWriter = new BitWriter();
bitWriter.writeInt(42, bits = 7);
assertEqual( bitWriter.data(), {0x42} )

Quindi l'idea è che il bitwriter sa come scrivere i tipi di campi più primitivi, come gli ints.

I tipi più complessi sarebbero stati implementati usando e testato qualcosa del tipo:

bitWriter = new BitWriter();
writeDate(bitWriter, new Datetime(2001, 10, 4));

bitWriter2 = new BitWriter();
bitWriter2.writeInt(2001, 12)
bitWriter2.writeInt(10, 4)
bitWriter2.writeInt(4, 6)

assertEquals(bitWriter.data(), bitWriter2.data() )

Si noti che questo evita qualsiasi conoscenza su come i bit attuali vengono impacchettati. Questo è stato testato dal test precedente e per questo test pensiamo che funzioni.

Quindi al prossimo livello di astrazione avremmo

bitWriter = new BitWriter();
encodeObject(bitWriter, myObject);


bitWriter2 = new BitWriter();
bitWriter2.writeInt(42, 32)
writeDate(bitWriter2, new Datetime(2001, 10, 4));
writeVarString(bitWriter2, "alphanumeric");

assertEquals(bitWriter.data(), bitWriter2.data() )

quindi, ancora una volta, non cerchiamo di includere la conoscenza di come le stringhe o le date oi numeri siano effettivamente codificati. In questo test, siamo interessati solo alla codifica prodotta da encodeObject.

Il risultato finale è che se il formato delle date viene modificato, dovrai correggere i test che implicano effettivamente le date, ma tutti gli altri codici e test non riguardano il modo in cui le date sono effettivamente codificate e una volta aggiornato codice per farlo funzionare, tutti quei test passeranno bene.

    
risposta data 14.02.2013 - 05:58
fonte
6

Dipende. Se la codifica è qualcosa di completamente fisso, in cui ogni implementazione dovrebbe creare esattamente lo stesso output, non ha senso controllare altro che verificare che gli input di esempio corrispondano esattamente agli output attesi. Questo è il test più ovvio e probabilmente anche il più facile da scrivere.

Se c'è spazio di manovra con uscite alternative, come nello standard MPEG (ad esempio ci sono alcuni operatori che puoi applicare all'input, ma sei libero di scambiare lo sforzo di codifica con la qualità di output o lo spazio di archiviazione), allora è meglio applicare la strategia di decodifica definita all'output e verificare che sia uguale all'immissione - o, se la codifica è lossy, che sia ragionevolmente vicina all'input originale. È più difficile da programmare, ma ti protegge da eventuali miglioramenti futuri che potrebbero essere apportati al tuo codificatore.

    
risposta data 13.02.2013 - 19:14
fonte
3

Prova che encode(decode(coded_value)) == coded_value e decode(encode(value)) == value . Puoi dare un input casuale ai test se vuoi.

È comunque possibile che sia l'encoder che il decoder siano rotti in modi complementari, ma ciò sembra abbastanza improbabile a meno che non si abbia un fraintendimento concettuale dello standard di codifica. I test hardcoded dell'encoder e del decodificatore (come si sta già facendo) dovrebbero proteggerli.

Se hai accesso a un'altra implementazione di questo che è noto per funzionare, puoi almeno usarla per avere la certezza che la tua implementazione è buona anche se l'utilizzo nei test di unità sarebbe impossibile.

    
risposta data 13.02.2013 - 22:20
fonte
2

Verifica i requisiti .

Se i requisiti sono solo 'codificare in un flusso di byte che quando decodificati produce un oggetto equivalente', quindi basta testare l'encoder decodificandolo. Se stai scrivendo sia il codificatore che il decodificatore, basta testarli insieme. Non possono avere "errori di corrispondenza". Se lavorano insieme, passa il test.

Se ci sono altri requisiti per il flusso di dati, dovrai testarli esaminando i dati codificati.

Se il formato codificato è predefinito, è necessario verificare i dati codificati rispetto al risultato previsto, o come (meglio) ottenere un decodificatore di riferimento che può essere considerato attendibile per effettuare la verifica. L'uso di un decodificatore di riferimento elimina la possibilità di aver interpretato erroneamente le specifiche del formato.

    
risposta data 13.02.2013 - 23:09
fonte
1

A seconda del framework di test e del paradigma che stai utilizzando, puoi comunque utilizzare il pattern Arrange Act Assert per questo come hai detto.

[TestMethod]
public void EncodeMyObject_ForValidInputs_Encodes()
{
    //Arrange object under test
    MyEncoder encoderUnderTest = new MyEncoder();
    MyObject validObject = new MyOjbect();
    //arrange object for condition under test

    //Act
    byte[] actual = encoderUnderTest.EncodeMyObject(myObject);

    //Assert
    byte[] expected = new byte[3]{ 0x01, 0x02, 0xFF };
    Assert.IsEqual(expected, actual);
}

Dovresti conoscere i requisiti per EncodeMyObject() e puoi utilizzare questo modello per testare ciascuno di essi per criteri validi e non validi, disponendo ognuno di essi e codificando il risultato previsto per expected , analogamente per il decodificatore.

Dal momento che le aspettative sono codificate in modo rigido, queste saranno fragili se avrai un enorme cambiamento.

Potresti essere in grado di automatizzare con qualche parametro guidato (dai un'occhiata a Pex ) o se stai facendo DDD o BDD dai uno sguardo a gerkin / cetriolo .

    
risposta data 13.02.2013 - 19:36
fonte
1

Devi decidere cosa è importante per te.

È importante per te che un oggetto sopravviva al viaggio di andata e il formato esatto del filo non è veramente importante? Oppure il formato filo esatto è una parte importante della funzionalità del codificatore e del decodificatore?

Se il primo, basta assicurarsi che gli oggetti sopravvivano al viaggio di andata e ritorno. Se l'encoder e il decodificatore sono entrambi spezzati in modi perfettamente complementari, non ti interessa davvero.

Se quest'ultimo, è necessario verificare che il formato del filo sia come previsto per gli input dati. Ciò significa testare il formato direttamente oppure utilizzare un'implementazione di riferimento. Tuttavia, dopo aver testato i principi di base, è possibile ottenere valore dai test di andata e ritorno aggiuntivi, che dovrebbero essere più semplici da scrivere in termini di volume.

    
risposta data 13.02.2013 - 22:41
fonte

Leggi altre domande sui tag