“ガラスボックス” *少ない*テストにつながるときにテストしますか?

StackOverflow https://stackoverflow.com/questions/203075

質問

たとえば、CsvReaderに対するテストを書いています。これは、テキストの行を列挙して分割する単純なクラスです。その唯一の raison d 'ê tre は、引用符内のコンマを無視します。 1ページ未満です。

「ブラックボックス」によるクラスをテストして、次のようなことを確認しました

  • ファイルが存在しない場合はどうなりますか
  • ファイルに対する許可がない場合はどうなりますか
  • ファイルにWindows以外の改行がある場合はどうなりますか?

実際には、これらすべてがStreamReaderのビジネスです。私のクラスは、これらのケースについて何もせずに機能します。したがって、本質的に、私のテストはStreamReaderによってスローされたエラーをキャッチし、フレームワークによって処理される動作をテストしています。何もしないで多くの仕事をしているように感じます。

関連する質問を見ました

私の質問は、「ガラスの箱」という点が欠けているということです。この種の作業を回避するために知っていることを使用するかどうかをテストしますか?

役に立ちましたか?

解決

これは実際にCsvReaderのインターフェースに依存します。クラスのユーザーが何を期待しているかを考慮する必要があります。

たとえば、パラメーターの1つがファイル名であり、ファイルが存在しない場合はどうなりますか?これは、ストリームリーダーを使用するかどうかに依存してはなりません。単体テストでは、クラスの観察可能な外部動作をテストし、場合によっては、少し掘り下げて、特定の実装の詳細がカバーされていることを確認する必要があります。リーダーが終了すると、ファイルは閉じられます。

ただし、ユニットテストがすべての詳細に依存したり、実装の詳細のために何かが発生すると仮定したりすることは望ましくありません。

質問で言及するすべての例には、クラスの観察可能な動作(この場合は例外的な状況)が含まれているため、それらに関連する単体テストが必要です。

他のヒント

あなたのコードではないものをテストするのに時間を浪費すべきではないと思います。基礎となるフレームワークのエラーを処理するか、呼び出し元に伝播させるかは、テストの選択ではなく設計上の選択です。 FWIW、私はあなたがそれらを広めるのは正しいと思います。ただし、設計上の決定を下した後は、基礎となるフレームワークをテストせずに、ユニットテストでコードをカバーする(そしてカバーする)必要があります。 依存性注入と模擬ストリームを使用することもおそらく良い考えです。

[EDIT]依存性注入の例(詳細については上記のリンクを参照)

依存性注入を使用していません:

public class CvsReader {
   private string filename;
   public CvsReader(string filename)
   {
      this.filename = filename;
   }

   public string Read()
   {
      StreamReader reader = new StreamReader( this.filename );
      string contents = reader.ReadToEnd();
      .... do some stuff with contents...
      return contents;
   }
}

依存性注入(コンストラクター注入)では、次のようにします。

public class CvsReader {
   private IStream stream;
   public CvsReader( IStream stream )
   {
      this.stream = stream;
   }

   public string Read()
   {
       StreamReader reader = new StreamReader( this.stream );
       string contents = reader.ReadToEnd();
       ...  do some stuff with contents ...
       return contents;
   }
}

これにより、CvsReaderをより簡単にテストできます。コンストラクター(この場合はIStream)で依存するインターフェイスを実装するインスタンスを渡します。このため、IStreamを実装する別のクラス(おそらくモッククラス)を作成できますが、必ずしもファイルI / Oを実行するわけではありません。このクラスを使用して、基になるフレームワークを使用せずに、必要なデータを読者に提供できます。この場合は、読み取り専用なので、MemoryStreamを使用します。ただし、モッククラスを使用して、テストが提供する応答を構成できるようにする、よりリッチなインターフェイスを提供することができます。このようにして、基礎となるフレームワークコードをまったく使用せずに、作成したコードをテストできます。あるいは、TextReaderを渡すこともできますが、通常の依存性注入パターンはインターフェイスを使用するため、インターフェイスでパターンを表示したかったのです。上記のコードはまだStreamReaderの実装に依存しているため、おそらくTextReaderを渡す方が良いでしょう。

はい。ただし、これは厳密に単体テストを目的としています。

特定のStreamReaderからCSVリーダーの実装を抽象化するには、抽象ストリームリーダーインターフェイスを定義し、そのインターフェイスを実装する模擬ストリームリーダーで独自の実装をテストします。モックリーダーは、存在しないファイル、アクセス許可の問題、OSの違いなどのエラーの影響を受けないことは明らかです。したがって、独自のコードを完全にテストし、100%のコードカバレッジを達成できます。

tvanfossonに同意する傾向があります。StreamReaderを継承して何らかの方法で拡張する場合、ユニットテストでは追加または変更した機能のみを実行する必要があります。そうしないと、多くの時間と認知エネルギーを無駄にし、価値をもたらさないテストの作成、読み取り、保守を行うことになります。

markjは正しいのですが、テストは「観察可能な外部の振る舞い」をカバーする必要があります。クラスの場合、その振る舞いがどこから来るかをどこで考慮するのが適切だと思います。別の(おそらく単体テスト済みの)クラスからの継承による動作の場合、独自の単体テストを追加してもメリットはありません。 OTOH、コンポジションを介した動作の場合、パススルーが適切に機能していることを確認するためにいくつかのテストを 正当化できます。

私が好むのは、変更する特定の機能を単体テストし、エラー状態をチェックする統合テストを作成することですが、ビジネスのコンテキストでは最終的にサポートする必要があります。

参考までに、これが.NETの場合は、車輪を再発明しないことを検討する必要があります。

C#の場合

Microsoft.VisualBasicへの参照を追加します 素晴らしいクラスのMicrosoft.VisualBasic.FileIO.TextFieldParser()を使用して、CSV解析のニーズを処理します。

Microsoftはすでにテストしているので、その必要はありません。

お楽しみください。

フレームワークがスローするエラーを常に管理する必要があります。そのようにして、アプリケーションは堅牢です&壊滅的なエラーでクラッシュしません...

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top