3

私はこのトピックを読んでいました。これは、リフレクションを使用してプライベート変数をテストすることについてです...

しかし、単体テストではそのような問題はなく、コードは完全にテスト可能です。

唯一の問題は、複雑なオブジェクトの各プロパティに対してアサーションを実行して期待される結果を得るには、非常に時間がかかることです。特に複雑なオブジェクトのリストの場合。

これは複雑なオブジェクトなので、オブジェクトごとに実装しない限り、法線Assert.AreEqualを実行しても正しい結果が得られません。IEquality

しかし、そうしても、アサーション中にどのプロパティ/フィールドの名前、期待値、および実際の値がわかりません。

正しくは、各プロパティ値を手動でリストに入れ、単一CollectionAssertionの . プロパティ名は教えてくれません。これにより、デバッグが非常に困難になります(デバッグモードに移動して、コレクション内の要素を確認する必要がありました)。

そこで、2 つの複雑なオブジェクトに対してアサーションを実行する再帰的なリフレクション メソッドを作成すると、すべてのプロパティ名、期待値、実際の値がわかります。

それは良い習慣ですか、それとも悪い習慣ですか?

4

5 に答える 5

1

多くの人はリフレクションを考慮に入れさえしないと思いますが、リフレクションにはその場所があります。他のポスターが述べているように、パフォーマンス、型の安全性などに関して間違いなく欠点がありますが、実際には単体テストはそれを使用するのに適した場所だと思います. 慎重に行われる限り。

プロパティで使用するすべてのタイプを所有していない場合、すべてのオブジェクトに同等の実装を強制しようとすると壁にぶつかります。また、100 のミニ比較クラスを実装することは、アサートを手動で書き出すのと同じくらい時間がかかります。

過去に、あなたが説明したことを行う拡張メソッドを作成しました:

  • 同じタイプの (または共通のインターフェースを実装する) 2 つのオブジェクトを比較します。
  • リフレクションは、すべてのパブリック プロパティを見つけるために使用されます。
  • プロパティが値型の場合、単純な Assert.AreEquals が実行されます
  • 参照型の場合、再帰呼び出しを行います

私のテストはプロパティ名をまったく気にしないので、名前変更のリファクタリングは重要ではありません。実際、新しいプロパティは自動的に検出され、削除されたプロパティは忘れられます。

本当に複雑なオブジェクトで使用したことはありませんが、テストを遅くすることなく、私が持っているオブジェクトではうまく機能しました.

したがって、私の意見では、単体テストではリフレクションを慎重に使用してください。

編集:私はあなたのために私の方法を掘り下げようとします.

于 2013-01-31T01:40:55.933 に答える
0

私の意見では、Reflectionを使用することはあまり良い選択肢ではありません。Reflectionを使用すると、コンパイル時に型の安全性が失われます。また、Reflectionの使用の背後には、アセンブリのメタデータを介した大文字と小文字を区別しない文字列検索があります。これにより、パフォーマンスが低下します。これらの側面を考慮すると、(oleksiiが推奨するように)元のタイプを分割することは1つの良いアプローチだと思います。

もう1つのアプローチは、純粋なアクセサーメソッドを使用して、個別のテストを作成し、個別の属性セットをテストすることです。これはすべての場合に適しているとは限りません。ただし、場合によってはそうなります。

例:Customerクラスがある場合、Address-typeフィールドをチェックするためのテストを1つ作成できます。Order-typeフィールドなどをチェックする別のテストを作成できます。

于 2013-01-30T22:35:25.287 に答える
0

通常の状況では、単体テストに関連することを行うためにリフレクションは必要ありませんこれは、リンクした質問への回答で言及されています。

リフレクションは本当に最後の手段にすぎません

複雑なオブジェクトが等しいかどうかをチェックする必要がある場合は、単体テストでそのような等価チェックを実装します。純粋に単体テストの目的で追加のコードを使用しても問題はありません。

public void ComplexObjectsAreEqual()
{
    var first = // ...
    var second = // ...

    AssertComplexObjectsAreEqual(first, second);
}

private void AssertComplexObjectsAreEqual(ComplexObject first,
    ComplexObject second)
{
    Assert.That(first.Property1, Is.EqualTo(second.Property1),
       "Property1 differs: {0} vs {1}", first.Property1, second.Property1); 
    // ...
}

単体テストを他のコードとして扱うべきではありません。それらをより読みやすく、クリーンで、保守しやすくするために何かを書く必要がある場合は、それを書いてください。それは他の場所と同じコードです。製品コードでリフレクションを介してオブジェクトを比較しますか?

于 2013-01-31T00:40:18.130 に答える
-1

私見、それは悪い習慣です。

  • リフレクション コードは遅く、正しく書くのが難しい
  • 維持するのはさらに難しく、そのようなコードはリファクタリングに適していない可能性があります
  • リフレクションは遅く、単体テストは高速でなければならない
  • それも気持ち悪い

私には、これは問題を解決するのではなく、穴を塞ごうとしているように見えます。この問題を解決するために、大規模で複雑なクラスをより小さな一連のクラスに分離することを提案できます。多くのプロパティがある場合 - それらを個々のクラスにグループ化します


だからそのようなクラス

class Foo
{
    T1 Prop1 {get; set;}
    T2 Prop2 {get; set;}
    T3 Prop3 {get; set;}
    T4 Prop4 {get; set;}
}

なるだろう

class Foo
{
    T12 Prop12 {get; set;}  
    T34 Prop34 {get; set;}  
}
class T12
{
    T1 Prop1 {get; set;}
    T2 Prop2 {get; set;}
}
class T34
{
    T3 Prop3 {get; set;}
    T4 Prop4 {get; set;}
}

Fooは 1 つのプロパティ (「グループ化された」表現) しか持っていないことに注意してください。ある方法でプロパティをグループ化して、状態の変化が特定のグループにローカライズされるようにすると、タスクが大幅に簡素化されます。次に、「グループ化された」プロパティが期待される状態と等しいことをアサートできます。

于 2013-01-30T22:03:53.620 に答える