Tienes un conflicto aquí.
Desea probar el valor de retorno de doThings()
, que se basa en un literal (valor constante).
Cualquier prueba que escriba para esto se reducirá inherentemente a la prueba de un valor constante , lo cual no tiene sentido.
Para mostrarle un ejemplo más sensible (soy más rápido con C #, pero el principio es el mismo)
public class TriplesYourInput : Base
{
public TriplesYourInput(int input)
{
this.foo = 3 * input;
}
}
Esta clase se puede probar de manera significativa:
var inputValue = 123;
var expectedOutputValue = inputValue * 3;
var receivedOutputValue = new TriplesYourInput(inputValue).doThings();
Assert.AreEqual(receivedOutputValue, expectedOutputValue);
Esto tiene más sentido para probar. Su salida se basa en la entrada que eligió darle. En tal caso, puede dar a una clase una entrada elegida arbitrariamente, observar su salida y probar si coincide con sus expectativas.
Algunos ejemplos de este principio de prueba. Tenga en cuenta que mis ejemplos siempre tienen control directo sobre cuál es la entrada del método comprobable.
- Pruebe si
GetFirstLetterOfString()
devuelve "F" cuando ingreso "Flater".
- Pruebe si
CountLettersInString()
devuelve 6 cuando ingreso "Flater".
- Probar si
ParseStringThatBeginsWithAnA()
devuelve una excepción cuando ingreso "Flater".
Todas estas pruebas pueden ingresar cualquier valor que deseen , siempre que sus expectativas estén en línea con lo que están ingresando.
Pero si su salida se decide por un valor constante, entonces tendrá que crear una expectativa constante y luego probar si el primero coincide con el segundo. Lo cual es una tontería, esto siempre o nunca va a pasar; ninguno de los cuales es un resultado significativo.
Algunos ejemplos de este principio de prueba. Observe que estos ejemplos no tienen control sobre al menos uno de los valores que se están comparando.
- Prueba si
Math.Pi == 3.1415...
- Prueba si
MyApplication.ThisConstValue == 123
Estas pruebas para un valor particular. Si cambia este valor, sus pruebas fallarán. En esencia, no está probando si su lógica funciona para cualquier entrada válida, simplemente está probando si alguien puede predecir con precisión un resultado sobre el cual no tiene control.
Eso es esencialmente probar el conocimiento del escritor de prueba de la lógica empresarial. No está probando el código, sino el propio escritor.
Volviendo a su ejemplo:
class BarDerived : public Base
{
public:
BarDerived() : Base(12) { };
~BarDerived() { };
int doBarThings() { return foo + 1; };
}
¿Por qué BarDerived
siempre tiene un foo
igual a 12
? ¿Cuál es el significado de este?
Y dado que ya has decidido esto, ¿qué estás tratando de ganar escribiendo una prueba que confirme que BarDerived
siempre tiene un foo
igual 12
?
Esto empeora aún más si comienzas a tener en cuenta que doThings()
se puede anular en una clase derivada. Imagínese si AnotherDerived
anulara doThings()
para que siempre regrese foo * 2
. Ahora, vas a tener una clase que está codificada como Base(12)
, cuyo doThings()
valor es 24. Si bien es técnicamente comprobable, carece de significado contextual. La prueba no es comprensible.
Realmente no puedo pensar en una razón para usar este enfoque de valor codificado. Incluso si hay un caso de uso válido, no entiendo por qué está intentando escribir una prueba para confirmar este valor codificado . No hay nada que ganar al probar si un valor constante es igual al mismo valor constante.
Cualquier falla en la prueba demuestra inherentemente que la prueba es incorrecta . No hay resultado cuando una falla en la prueba demuestra que la lógica del negocio es incorrecta. De hecho, no puede confirmar qué pruebas se crean para confirmar en primer lugar.
El problema no tiene nada que ver con la herencia, en caso de que te lo estés preguntando. Que acaba de pasar a haber utilizado un valor const en el constructor de la clase base, pero que podría haber utilizado este valor const cualquier otro lugar y entonces no estaría relacionado con una clase heredada.
Editar
Hay casos en que los valores codificados no son un problema. (de nuevo, perdón por la sintaxis de C # pero el principio sigue siendo el mismo)
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) {}
}
Si bien el valor constante ( 2
/ 3
) todavía influye en el valor de salida de GetMultipliedValue()
, el consumidor de su clase todavía tiene control sobre él.
En este ejemplo, aún se pueden escribir pruebas significativas:
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);
- Técnicamente, todavía estamos escribiendo una prueba que verifica si la constante en
base(value, 2)
coincide con la constante inputValue * 2
.
- Sin embargo, al mismo tiempo también estamos probando que esta clase está multiplicando correctamente cualquier valor dado por este factor predeterminado .
El primer punto no es relevante para la prueba. El segundo es!
virtual
?