ここで対立があります。
リテラル(定数値)にdoThings()
依存するの戻り値をテストするとします。
このために作成するテストは、本質的に、無意味なconst値のテストを煮詰めます。
より意味のある例を示すため(C#の方が速いですが、原則は同じです)
public class TriplesYourInput : Base
{
public TriplesYourInput(int input)
{
this.foo = 3 * input;
}
}
このクラスは有意義にテストできます:
var inputValue = 123;
var expectedOutputValue = inputValue * 3;
var receivedOutputValue = new TriplesYourInput(inputValue).doThings();
Assert.AreEqual(receivedOutputValue, expectedOutputValue);
これはテストする方が理にかなっています。その出力は、あなたがその入力に基づいて選んだそれを与えるために。このような場合、クラスに任意に選択された入力を与え、その出力を観察し、それが期待と一致するかどうかをテストできます。
このテスト原理のいくつかの例。私の例では常に、テスト可能なメソッドの入力を直接制御していることに注意してください。
GetFirstLetterOfString()
「Flater」と入力して「F」を返すかどうかをテストします。
CountLettersInString()
「Flater」と入力して6を返すかどうかをテストします。
ParseStringThatBeginsWithAnA()
「Flater」と入力して例外を返すかどうかをテストします。
これらのテストはすべて、期待が入力内容と一致している限り、任意の値を入力できます。
しかし、出力が定数値によって決定される場合は、一定の期待値を作成し、最初のものが2番目に一致するかどうかをテストする必要があります。これはばかげています。これは常に成功するか、まったく成功しないかのどちらかです。どちらも意味のある結果ではありません。
このテスト原理のいくつかの例。これらの例では、比較される値の少なくとも1つを制御できないことに注意してください。
- テストする
Math.Pi == 3.1415...
- テストする
MyApplication.ThisConstValue == 123
これらのテストでは、特定の値が1つあります。この値を変更すると、テストは失敗します。本質的に、ロジックが有効な入力に対して機能するかどうかをテストするのではなく、誰かが制御できない結果を正確に予測できるかどうかをテストするだけです。
これは基本的に、テストライターのビジネスロジックに関する知識をテストすることです。コードのテストではなく、作成者自身がテストします。
あなたの例に戻る:
class BarDerived : public Base
{
public:
BarDerived() : Base(12) { };
~BarDerived() { };
int doBarThings() { return foo + 1; };
}
なぜBarDerived
常にfoo
と等しい12
ですか?これの意味は何ですか?
そして、これをすでに決定しているとすると、BarDerived
常にがとfoo
等しいことを確認するテストを書くことによって何を獲得しようとしてい12
ますか?
因数分解を開始doThings()
すると、派生クラスでオーバーライドされる可能性があるため、これはさらに悪化します。それが常に戻るようAnotherDerived
にオーバーライドdoThings()
する場合を想像してくださいfoo * 2
。あなたのようにハードコードされたクラスの必要があるとしている今、Base(12)
その、doThings()
値が技術的に検証可能なものの24であるが、それはどんな文脈の意味を欠いています。テストは包括的ではありません。
このハードコードされた値のアプローチを使用する理由は本当に思いつきません。有効なユースケースがある場合でも、このハードコーディングされた値を確認するためのテストを作成しようとしている理由がわかりません。定数値が同じ定数値と等しいかどうかをテストすることによって得るものはありません。
テストの失敗は、本質的にテストが間違っていることを証明します。テストの失敗がビジネスロジックが間違っていることを証明する結果はありません。最初に確認するために作成されたテストを確認することは事実上不可能です。
あなたが疑問に思っていた場合、問題は継承とは何の関係もありません。あなただけ起こる基底クラスのコンストラクタでconstの値を使用しているために、しかし、あなたはどこにも、このconstの値を使用していたかもしれないし、それを継承したクラスに関連することではないでしょう。
編集する
ハードコードされた値が問題にならない場合があります。(繰り返しますが、C#の構文で申し訳ありませんが、原則は同じです)
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) {}
}
一定の値(一方で2
/は3
)まだの出力値に影響を与えているGetMultipliedValue()
、あなたのクラスの消費者はまだあまりにもそれを制御しています!
この例でも、意味のあるテストを書くことができます。
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);
- 技術的には、const inがconst inと
base(value, 2)
一致するかどうかをチェックするテストをまだ書いていますinputValue * 2
。
- ただし、同時に、このクラスが任意の値にこの所定の係数を正しく乗算していることもテストしています。
最初の箇条書きはテストには関係ありません。二つ目は!
virtual
ですか?