3

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

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

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

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

関連する質問を見てきました

私の質問は、この種の作業を回避するために知っていることを使用する場合、「ガラスの箱」テストのポイントを見逃しているのでしょうか?

4

6 に答える 6

3

コード以外のものをテストするのに時間を無駄にするべきではないと思います。基盤となるフレームワークのエラーを処理するか、呼び出し元に伝播させるかは、テストの選択ではなく、設計上の選択です。FWIW、私はあなたがそれらを繁殖させるのは正しいと思います。ただし、設計上の決定を下したら、単体テストでは、基盤となるフレームワークをテストせずに、コードをカバーする(そして十分にカバーする)必要があります。依存性注入とモックストリームを使用することもおそらく良い考えです。

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

依存性注入を使用しない場合:

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から読み取るだけなので、MemoryStreamを使用します。ただし、モッククラスを使用して、テストで提供される応答を構成できる、よりリッチなインターフェイスを提供することもできます。このようにして、作成したコードをテストでき、基盤となるフレームワークコードはまったく含まれません。または、TextReaderを渡すこともできます。しかし、通常の依存性注入パターンはインターフェースを使用しているので、インターフェースを使用してパターンを表示したいと思いました。上記のコードは依然としてStreamReaderの実装に依存しているため、おそらくTextReaderを渡す方がよいでしょう。

于 2008-10-14T23:11:13.523 に答える
3

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

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

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

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

于 2008-10-14T23:11:18.250 に答える
2

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

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

于 2008-10-14T22:42:12.617 に答える
1

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

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

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

于 2008-10-15T21:33:39.853 に答える
1

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

C# の場合

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

Microsoft は既にテスト済みなので、テストする必要はありません。

楽しみ。

于 2010-08-26T18:29:42.037 に答える
0

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

于 2008-10-14T22:23:38.363 に答える