Hai un conflitto qui.
Vuoi testare il valore di ritorno di doThings()
, che si basa su un valore letterale (valore const).
Ogni test che scrivi per questo è in grado di riassumere testare un valore const , che è privo di senso.
Per mostrarti un esempio più sensato (sono più veloce con C #, ma il principio è lo stesso)
public class TriplesYourInput : Base
{
public TriplesYourInput(int input)
{
this.foo = 3 * input;
}
}
Questa classe può essere testata in modo significativo:
var inputValue = 123;
var expectedOutputValue = inputValue * 3;
var receivedOutputValue = new TriplesYourInput(inputValue).doThings();
Assert.AreEqual(receivedOutputValue, expectedOutputValue);
Questo ha più senso da testare. Il suo output si basa sull'input che ha scelto per darlo. In tal caso, puoi assegnare a una classe un input scelto arbitrariamente, osservarne l'output e verificare se corrisponde alle tue aspettative.
Alcuni esempi di questo principio di prova. Si noti che i miei esempi hanno sempre un controllo diretto su quale sia l'input del metodo testabile.
- Test if
GetFirstLetterOfString()
return "F" when I input "Flater".
- Test if
CountLettersInString()
returns 6 when I input "Flater".
- Test if
ParseStringThatBeginsWithAnA()
returns an exception when I input "Flater".
Tutti questi test possono inserire qualsiasi valore vogliano , a patto che le loro aspettative siano in linea con quello che stanno inserendo.
Ma se il tuo output è deciso da un valore costante, dovrai creare un'aspettativa costante, quindi testare se il primo corrisponde al secondo. Il che è sciocco, questo è sempre o mai che passerà; nessuno dei quali è un risultato significativo.
Alcuni esempi di questo principio di prova. Nota che questi esempi non hanno alcun controllo su almeno uno dei valori che vengono confrontati.
- Test if
Math.Pi == 3.1415...
- Test if
MyApplication.ThisConstValue == 123
Questi test per uno valore particolare. Se cambi questo valore, i tuoi test falliranno. In sostanza, non stai testando se la tua logica funziona per qualsiasi input valido, stai semplicemente testando se qualcuno è in grado di prevedere con precisione un risultato su cui non hanno alcun controllo.
Questo è essenzialmente il test della conoscenza dello scrittore di test della logica di business. Non sta testando il codice, ma lo stesso autore.
Ripristina il tuo esempio:
class BarDerived : public Base
{
public:
BarDerived() : Base(12) { };
~BarDerived() { };
int doBarThings() { return foo + 1; };
}
Perché BarDerived
ha sempre un foo
uguale a 12
? Qual è il significato di questo?
E visto che hai già deciso questo, cosa stai cercando di guadagnare scrivendo un test che conferma che BarDerived
ha sempre un foo
uguale a 12
?
Questo diventa ancora peggio se inizi a prendere in considerazione che doThings()
può essere sovrascritto in una classe derivata. Immagina se AnotherDerived
debba sostituire doThings()
in modo che restituisca sempre foo * 2
. Ora, avrai una classe che è hardcoded come Base(12)
, il cui valore doThings()
è 24. Sebbene tecnicamente testabile, è privo di qualsiasi significato contestuale. Il test non è comprensibile.
Non riesco davvero a pensare a un motivo per utilizzare questo approccio al valore codificato. Anche se esiste un caso di utilizzo valido, non capisco perché stai provando a scrivere un test per confermare questo valore codificato . Non c'è nulla da guadagnare testando se un valore costante è uguale allo stesso valore costante.
Qualsiasi errore di test dimostra che il test è sbagliato . Non vi è alcun risultato in cui un errore di test dimostra che la logica aziendale è sbagliata. In effetti, non sei in grado di confermare quali test sono stati creati per confermare in primo luogo.
Il problema non ha nulla a che fare con l'ereditarietà, nel caso ve lo stiate chiedendo. Devi solo accadere per aver usato un valore const nel costruttore della classe base, ma avresti potuto usare questo valore const altrove e quindi non sarebbe stato correlato a una classe ereditata.
Modifica
Ci sono casi in cui i valori hardcoded non sono un problema. (ancora, mi dispiace per la sintassi C # ma il principio è sempre lo stesso)
public class Base
{
public int MultiplyFactor;
protected int InitialValue;
public Base(int value, int factor)
{
this.InitialValue = value;
this.MultiplyFactor= factor;
}
public int GetMultipliedValue()
{
return this.InitialValue * this.MultiplyFactor;
}
}
public class DoublesYourNumber : Base
{
public DoublesYourNumber(int value) : base(value, 2) {}
}
public class TriplesYourNumber : Base
{
public TriplesYourNumber(int value) : base(value, 3) {}
}
Mentre il valore costante ( 2
/ 3
) sta ancora influenzando il valore di output di GetMultipliedValue()
, il consumatore della tua classe ha ancora il controllo su di esso anche!
In questo esempio, è comunque possibile scrivere test significativi:
var inputValue = 123;
var expectedDoubledOutputValue = inputValue * 2;
var receivedDoubledOutputValue = new DoublesYourNumber(inputValue).GetMultipliedValue();
Assert.AreEqual(expectedDoubledOutputValue , receivedDoubledOutputValue);
var expectedTripledOutputValue = inputValue * 3;
var receivedTripledOutputValue = new TriplesYourNumber(inputValue).GetMultipliedValue();
Assert.AreEqual(expectedTripledOutputValue , receivedTripledOutputValue);
- Tecnicamente, stiamo ancora scrivendo un test che verifica se il const in
base(value, 2)
corrisponde al const in inputValue * 2
.
- Tuttavia, siamo allo stesso tempo anche testando che questa classe sia correttamente moltiplicando qualsiasi valore dato da questo fattore predeterminato .
Il primo punto elenco non è rilevante per il test. Il secondo è!