Você tem um conflito aqui.
Você deseja testar o valor de retorno de doThings()
, que depende de um literal (valor const).
Qualquer teste que você escrever para isso é inerentemente reduzir o teste de um valor constante , que é sem sentido.
Para mostrar um exemplo mais sensato (sou mais rápido com C #, mas o princípio é o mesmo)
public class TriplesYourInput : Base
{
public TriplesYourInput(int input)
{
this.foo = 3 * input;
}
}
Esta classe pode ser testada de forma significativa:
var inputValue = 123;
var expectedOutputValue = inputValue * 3;
var receivedOutputValue = new TriplesYourInput(inputValue).doThings();
Assert.AreEqual(receivedOutputValue, expectedOutputValue);
Isso faz mais sentido testar. Sua saída é baseada na entrada que você escolheu para fornecer. Nesse caso, você pode dar a uma classe uma entrada arbitrariamente escolhida, observar sua saída e testar se ela corresponde às suas expectativas.
Alguns exemplos desse princípio de teste. Observe que meus exemplos sempre têm controle direto sobre o que é a entrada do método testável.
- 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".
Todos esses testes podem inserir qualquer valor que quiserem , desde que suas expectativas estejam alinhadas com o que estão inserindo.
Mas se sua saída for decidida por um valor constante, você terá que criar uma expectativa constante e, em seguida, testar se a primeira corresponde à segunda. O que é bobo, isso é sempre ou nunca vai passar; nenhum dos quais é um resultado significativo.
Alguns exemplos desse princípio de teste. Observe que esses exemplos não têm controle sobre pelo menos um dos valores que estão sendo comparados.
- Test if
Math.Pi == 3.1415...
- Test if
MyApplication.ThisConstValue == 123
Esses testes valem para um valor específico um . Se você alterar esse valor, seus testes falharão. Em essência, você não está testando se sua lógica funciona para qualquer entrada válida, você está simplesmente testando se alguém é capaz de prever com precisão um resultado sobre o qual eles não têm controle.
Isso é essencialmente testar o conhecimento do autor do teste sobre a lógica de negócios. Não está testando o código, mas o próprio escritor.
Voltando ao seu exemplo:
class BarDerived : public Base
{
public:
BarDerived() : Base(12) { };
~BarDerived() { };
int doBarThings() { return foo + 1; };
}
Por que BarDerived
sempre tem foo
igual a 12
? Qual é o significado disso?
E, como você já decidiu isso, o que você está tentando obter ao escrever um teste que confirme que BarDerived
sempre tem foo
igual a 12
?
Isso fica ainda pior se você começar a considerar que doThings()
pode ser substituído em uma classe derivada. Imagine se AnotherDerived
substituísse doThings()
para que sempre retornasse foo * 2
. Agora, você terá uma classe que é codificada como Base(12)
, cujo valor doThings()
é 24. Embora tecnicamente testável, ela é desprovida de qualquer significado contextual. O teste não é compreensível.
Eu realmente não consigo pensar em um motivo para usar essa abordagem de valor codificado. Mesmo se houver um caso de uso válido, não entendo por que você está tentando escrever um teste para confirmar esse valor codificado . Não há nada a ganhar testando se um valor constante é igual ao mesmo valor constante.
Qualquer falha de teste prova que o teste está errado . Não há nenhum resultado em que uma falha de teste comprove que a lógica de negócios está errada. Você é efetivamente incapaz de confirmar quais testes são criados para confirmar, em primeiro lugar.
O problema não tem nada a ver com herança, caso você esteja se perguntando. Você acabou de acontecer ter usado um valor const no construtor da classe base, mas você poderia ter usado esse valor const em qualquer outro lugar e então não estaria relacionado a uma classe herdada.
Editar
Existem casos em que os valores codificados não são um problema. (mais uma vez, desculpe pela sintaxe do C #, mas o princípio ainda é o mesmo)
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) {}
}
Enquanto o valor constante ( 2
/ 3
) ainda está influenciando o valor de saída de GetMultipliedValue()
, o consumidor da sua classe ainda tem controle sobre ele também!
Neste exemplo, testes significativos ainda podem ser escritos:
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, ainda estamos escrevendo um teste que verifica se a const em
base(value, 2)
corresponde à const em inputValue * 2
.
- No entanto, estamos ao mesmo tempo testando também que essa classe está corretamente multiplicando qualquer valor determinado por esse fator predeterminado .
O primeiro ponto não é relevante para o teste. O segundo é!