5

私はこのメソッドシグネチャを持っています:List<ITMData> Parse(string[] lines)

ITMData35のプロパティがあります。

このようなパーサーをどのように効果的にテストしますか?

質問:

  • ファイル全体をロードする必要がありますか(System.IOを使用できますか)?
  • ファイルの行を文字列定数に入れる必要がありますか?
  • 1つ以上の行をテストする必要があります
  • ITMDataの各プロパティをテストする必要がありますか、それともオブジェクト全体をテストする必要がありますか?
  • テストの名前はどうですか?

編集

メソッドシグネチャをに変更しました ITMData Parse(string line)

テストコード:

[Subject(typeof(ITMFileParser))]
public class When_parsing_from_index_59_to_79
{
    private const string Line = ".........";
    private static ITMFileParser _parser;
    private static ITMData _data;

    private Establish context = () => { _parser = new ITMFileParser(); };

    private Because of = () => { _data = _parser.Parse(Line); };

    private It should_get_fldName = () => _data.FldName.ShouldBeEqualIgnoringCase("HUMMELDUMM");
}

編集2

クラスごとに1つのプロパティのみをテストする必要があるかどうかはまだわかりません。私の意見では、これにより、仕様に関するより多くの情報を提供できます。つまり、インデックス59からインデックス79までの1行を解析すると、fldNameが取得されます。1つのクラス内のすべてのプロパティをテストすると、この情報が失われます。テストを過剰に指定していますか?

私のテストは次のようになります。

[Subject(typeof(ITMFileParser))]
public class When_parsing_single_line_from_ITM_file
{
    const string Line = ""

    static ITMFileParser _parser;
    static ITMData _data;

    Establish context = () => { _parser = new ITMFileParser(); };

    private Because of = () => { _data = _parser.Parse(Line); };

    It should_get_fld??? = () => _data.Fld???.ShouldEqual(???);
    It should_get_fld??? = () => _data.Fld???.ShouldEqual(???);
    It should_get_fld??? = () => _data.Fld???.ShouldEqual(???);
    It should_get_fld??? = () => _data.Fld???.ShouldEqual(???);
    It should_get_fld??? = () => _data.Fld???.ShouldEqual(???);
    It should_get_fld??? = () => _data.Fld???.ShouldEqual(???);
    It should_get_fld??? = () => _data.Fld???.ShouldEqual(???);
    ...

}
4

4 に答える 4

4

ファイル全体をロードする必要がありますか(System.IOを使用できますか)?

これを行うと、単体テストではなくなり、統合テストまたは回帰テストになります。単体テストでは表示されない可能性のあるバグが表示されることが予想される場合は、これを実行できます。しかし、それはあまりありそうにありません。

少なくとも最初は、単体テストを使用したほうがよいでしょう。

ファイルの行を文字列定数に入れる必要がありますか?

同じ入力行を使用する複数のテストを作成する場合は、必ず確認してください。しかし、個人的には、それぞれが異なる入力文字列を渡す、さまざまなテストを作成する傾向があります。その時点で、定数を作成する理由はあまりありません(テストメソッド内で宣言されたローカル定数でない限り)。

1つ以上の行をテストする必要がありますか?

指定しませんでしたが、出力は入力と1対1であると想定します。つまり、3つの文字列を渡すと、3つITMDataのsが返されます。その場合、複数行のテストの必要性は制限されます。

ほとんどの場合、縮退したケースをテストする価値があります。この場合、空の文字列配列(ゼロ行)になります。また、反復でばかげた間違いがないことを確認できるように、複数の行を含むテストを少なくとも1つ行うことはおそらく価値があります。

ただし、出力が入力と1対1である場合は、実際に別のメソッドを使用する必要がありますParseSingleLine。メソッドが必要です。そうすれば、あなたParseは行を繰り返して呼び出すことに他なりませんParseSingleLine。Parseにはまだいくつかのテストが必要ですが、ほとんどのテストはに焦点を当てていParseSingleLineます。

于 2011-08-18T21:00:28.753 に答える
2

このような問題に直面した場合、通常は次のようにします。

事前に1つの短い免責事項:私は、個々の行をテストするよりも、「統合テスト」または「パーサー全体をテストする」ルートをたどると思います。過去に、実装の詳細が大量にテストに漏れて、実装の詳細を変更したときにテストを頻繁に変更しなければならないという状況に何度も直面しました。過剰仕様の典型的なケースだと思います;-/

  1. パーサーにファイルの読み込みを含めません。@mquanderが提案したように、代わりに入力パラメーターとしてTextReaderまたはIEnumerableを使用したいと思います。これにより、メモリ内のパーサー入力を指定でき、ファイルシステムに触れる必要がないため、テストが大幅に高速化されます。
  2. 私はテストデータを手作業でローリングするのが好きではないので、ほとんどの場合、埋め込みリソースとResourceManagerを使用して、assembly.GetManifestResource()を介して仕様アセンブリから直接テストデータをロードしています。私のソリューションには通常、リソースの読み取りを合理化するための多数の拡張メソッドがあります(TextReader TextResource.Load( "NAME_OF_SOME_RESOURCE")など)。
  3. MSpecについて:ファイルごとに1つのクラスを使用して解析しています。解析された結果でテストされるプロパティごとに、個別の(It)アサーションがあります。これらは通常1つのライナーであるため、追加のコーディング量はそれほど大きくありません。ドキュメントと診断に関しては、プロパティが正しく解析されていない場合、ソースを調べたり行番号を検索したりしなくても、どのアサーションが失敗したかを直接確認できるため、これは大きなプラスです。MSpec結果ファイルにも表示されます。さらに、失敗した他のアサーションを非表示にしないでください(1つのアサーションを修正して、次のアサーションの次の行で仕様が失敗するのを確認するだけの状況)。もちろん、これはあなたがあなたの仕様で使用する言葉遣いについてもっと考えることをあなたに強いますが、私にとってそれは私にとっても大きなプラスです 言語が思考を形成するという考えの支持者。言い換えれば、アサーションに名前を付ける方法がわからない場合は、仕様または実装のいずれかについておそらく何か怪しいことがあります。
  4. パーサーのメソッドシグネチャについて:List <T>や配列のような具体的な型は返さず、可変のList<T>型も返さないことをお勧めします。ここで基本的に言っているのは、「ねえ、私が終了した後、解析結果をいじくり回すことができる」ということです。これは、ほとんどの場合、おそらくあなたが望まないことです。代わりにIEnumerable<T>を返すことをお勧めします(または、後で本当に変更する必要がある場合はICollection <T>)
于 2011-08-31T15:37:15.170 に答える
1

私は通常、エッジケースとともに、一般的な成功と失敗のシナリオを検討しようとします。要件は、適切なユースケースを設定するのにも役立ちます。さまざまなシナリオを列挙するためにPexを検討してください。

于 2011-08-16T13:11:02.457 に答える
0

あなたの新しい質問について:

ITMDataの各プロパティをテストする必要がありますか、それともオブジェクト全体をテストする必要がありますか?

安全を確保したい場合は、各プロパティが一致したことを確認するテストを少なくとも1つ実行する必要があります。

テストの名前はどうですか?

このトピックのように、このトピックについてはかなりの数の議論があります。一般的なルールは、ユニットテストクラスに複数のメソッドがあり、それぞれが特定の何かをテストすることを目的としているということです。あなたの場合、それは次のようなものかもしれません:

public void Check_All_Properties_Parsed_Correctly(){.....}

public void Exception_Thrown_If_Lines_Is_Null(){.....}

public void Exception_Thrown_If_Lines_Is_Wrong_Length(){.....}

つまり、パーサーに対して「正しい」と見なす正確な動作をテストします。これが完了すると、パーサーコードに変更を加えるときに、何も壊れていないことを確認するための包括的なテストスイートができるため、はるかに安心できます。実際に頻繁にテストし、変更を加えたときにテストを最新の状態に保つことを忘れないでください。MSDNには、単体テストとテスト駆動開発に関するかなり優れたガイドがあります。

一般的に、私はあなたが少しグーグルすることによってあなたの質問のほとんどに対する答えを見つけることができると思います。テスト駆動開発に関する優れた本もいくつかあり、TDDの方法だけでなく、その理由も理解できます。言語に比較的依存しないプログラミングをしている場合は、Kent Beckのテスト駆動開発の例をお勧めします。それ以外の場合は、Microsoft.NETのテスト駆動開発のようなものをお勧めします。これらはあなたを非常に迅速に正しい軌道に乗せるはずです。

編集:

テストを過剰に指定していますか?

私の意見では、そうです。具体的には、私はあなたの次の行に同意しません:

1つのクラス内のすべてのプロパティをテストすると、この情報が失われます。

どのようにして正確に情報を失いますか?テストごとに新しいクラスを作成する以外に、このテストを実行する方法が2つあるとします。

  1. プロパティごとに異なるメソッドを用意します。テストメソッドは、などと呼ばれる可能性がありCheckPropertyXますCheckPropertyY。テストを実行すると、合格したフィールドと失敗したフィールドが正確に表示されます。これは明らかにあなたの要件を満たしていますが、それでもやり過ぎだと思います。オプション2を使用します。
  2. いくつかの異なる方法があり、それぞれが1つの特定の側面をテストします。これは私が最初に勧めたものであり、あなたが言及していることだと思います。テストの1つが失敗すると、メソッドごとに最初に失敗したものに関する情報のみが取得されますが、Assertを適切にコーディングすると、どのプロパティが正しくないかが正確にわかります。次のコードを検討してください。

Assert.AreEqual("test1", myObject.PropertyX, "Property X was incorrectly parsed"); Assert.AreEqual("test2", myObject.PropertyY, "Property Y was incorrectly parsed");

それらの1つが失敗すると、どの行が失敗したかがわかります。関連するエラーを修正し、テストを再実行すると、他のプロパティが失敗したかどうかを確認できます。プロパティごとにクラスまたはメソッドを作成すると、コードが多すぎて最新の状態に保つための作業が多すぎるため、これは一般的にほとんどの人が採用するアプローチです。

于 2011-08-24T05:53:08.430 に答える