6

私のクラスの履歴追跡部分を抽象化して、次のようにします。

private readonly Stack<MyObject> _pastHistory = new Stack<MyObject>();

internal virtual Boolean IsAnyHistory { get { return _pastHistory.Any(); } }

internal virtual void AddObjectToHistory(MyObject myObject)
{
  if (myObject == null) throw new ArgumentNullException("myObject");
  _pastHistory.Push(myObject);
}

internal virtual MyObject RemoveLastObject()
{
  if(!IsAnyHistory) throw new InvalidOperationException("There is no previous history.");
  return _pastHistory.Pop();
}

私の問題は、Remove が最後に追加されたオブジェクトを返すことを単体テストしたいということです。

  • AddObjectToHistory
  • RemoveObjectToHistory->経由で入力されたものを返しますAddObjectToHistory

ただし、最初に Add を呼び出す必要がある場合、それは実際には単体テストではありませんか? しかし、真の単体テストの方法でこれを行うことができる唯一の方法は、コンストラクターで Stack オブジェクトを渡すか、モックアウトすることIsAnyHistoryです...しかし、私の SUT をモックすることも奇妙です。それで、私の質問は、独断的な観点から、これは単体テストですか? そうでない場合、どうすればクリーンアップできますか...コンストラクターインジェクションが私の唯一の方法ですか? 単純なオブジェクトを渡さなければならないのは、一見無理があるように思えますか? この単純なオブジェクトでも押し出して注入しても大丈夫ですか?

4

5 に答える 5

4

これらのシナリオには 2 つのアプローチがあります。

  1. スタックの作成_pastHistory internal/または注入など、設計への干渉protected
  2. 他の (場合によっては単体テスト済みの) メソッドを使用して検証を実行する

いつものように、ゴールデン ルールはありませんが、単体テストが設計の変更を強制する状況は避けるべきだと思います (これらの変更は、コードの消費者にあいまいさ/不要な質問をもたらす可能性が高いため)。

とはいえ、最終的には、単体テスト コードが設計にどの程度干渉するか (最初のケース)、または完全な単体テスト定義を曲げるか (2 番目のケース) を検討しなければならないのはあなたです。

通常、2 番目のケースの方がはるかに魅力的です。元のクラス コードが乱雑になることはなく、Add既にテスト済みである可能性が高いため、信頼しても安全です。

于 2013-06-24T19:43:36.003 に答える
1

私の 2 セント...クライアントは、削除が機能したかどうかをどのように知ることができますか? 「クライアント」はこのオブジェクトとどのようにやり取りすることになっていますか? クライアントは履歴トラッカーにスタックをプッシュしますか? テスト対象の別のユーザー/消費者/クライアントとしてテストを扱います..実際の本番環境とまったく同じ相互作用を使用します。テスト対象のオブジェクトで複数のメソッドを呼び出すことは許可されていないという規則は聞いたことがありません。

シミュレートするために、スタックは空ではありません。Add - 99% ケースと呼ぶだけです。私はそのオブジェクトのカプセル化を破壊することを控えたいと思います..オブジェクトを人間のように扱います(オブジェクト思考でそれを読んだと思います)。何かをするように言ってください.. 侵入して入らないでください。

たとえば、誰かの財布にお金を入れてもらいたい場合は、

  • 簡単な方法は、彼らにお金を渡して、内部的に自分の財布に入れさせることです。
  • 財布を捨て、財布をポケットに入れます。

私はオプション1が好きです。また、実装の詳細 (テストで脆弱性を引き起こす) から解放される方法も参照してください。明日、その人がオンラインウォレットを使用することに決めたとしましょう。後者のアプローチは、オブジェクトの動作が壊れていなくても、テストを中断します。オンライン ウォレットを今すぐプッシュするには、テストを更新する必要があります。

私が見た別の例は、Repository.GetX() をテストするためのものです。ここでは、単体テストで SQL を使用してレコードを挿入するために DB に侵入し、Repository.AddX(x ) 最初。孤立は望ましいことですが、現実主義を覆すほどではありません。

ここであまり強くなりすぎないことを願っています.. オブジェクト API が「テスト容易性のためにゆがめられ」、もはや「機能する最も単純なもの」に似ていないところを見るのは苦痛です。

于 2013-06-25T05:13:18.880 に答える
1

MyObject が単純なオブジェクトであると仮定すると、これはまだ単体テストだと思います。単体テスト メソッドへの入力パラメーターを作成することがよくあります。

私はMichael Feather の単体テスト基準を使用します:

次の場合、テストは単体テストではありません。

  • データベースと通信します
  • ネットワークを介して通信します
  • ファイルシステムに触れる
  • 他の単体テストと同時に実行することはできません
  • それを実行するには、環境に対して特別なこと (構成ファイルの編集など) を行う必要があります。

これらのことを行うテストは悪くありません。多くの場合、それらは書く価値があり、単体テスト ハーネスで記述できます。ただし、変更を加えるたびに高速に実行できる一連のテストを保持できるように、それらを実際の単体テストから分離できることが重要です。

于 2013-06-24T19:17:33.003 に答える
0

他の回答で述べたように、あなたのオプションはそのように分類できると思います。

  1. テスト方法論に独断的なアプローチを採用し、スタック オブジェクトのコンストラクター インジェクションを追加して、独自の偽のスタック オブジェクトをインジェクトし、メソッドをテストできるようにします。

  2. add と remove 用に別のテストを作成します。remove テストは add メソッドを使用しますが、それをテスト セットアップの一部と見なします。追加テストに合格する限り、削除も成功するはずです。

于 2013-06-24T20:50:52.470 に答える