web-dev-qa-db-ja.com

テスト用のプライベートセッターによるプロパティのスタブ

私たちはオブジェクトを持っています

public class MyObject{
    protected MyObject(){}

    public string Property1 {get;private set;}
    public string Property2 {get;private set;}
    public string Property3 {get;private set;}
    public string Property4 {get;private set;}
    public string Property5 {get;private set;}
    public string Property6 {get;private set;}
    public string Property7 {get;private set;}
    public string Property8 {get;private set;}
    public string Property9 {get;private set;}
    public string Property10 {get;private set;}
}

本番コードでは、オートマッパーを介してこのオブジェクトを設定します。プロパティにアクセスして正しく設定できます。

このクラスを将来のパイプラインでテストする場合、プロパティにダミー値(テスト対象)を設定することはできません。

利用可能なオプションがいくつかあります。

  • テストに必要なパラメーターを受け入れ、プロパティを設定するカスタムコンストラクター。現在、3つのコンストラクターが必要です。コンストラクタはビジネス機能を提供しないため、これはクリーンではありません。

  • プロパティを仮想化して、クラスをスタブできるようにします。しかし、プロパティをvirtualにマークしても、ビジネス上の価値はなく、クラスを汚染します。

  • オブジェクトビルダーをクラスに追加して、内部でオブジェクトを構築します。ここでも、ビジネス上の付加価値はありません。おそらく少しすっきりしていますが、ドメインオブジェクト内の関連性のないコードがたくさんあります。

ここに提案、アドバイス、代替オプションはありますか?

10
JMan

いくつかのオプションがあります。

  • 先に進んで、カスタムコンストラクター、仮想プロパティ、またはオブジェクトビルダーを使用してください。これの背後にある理論的根拠は、オブジェクトが独立しているべきであり、オートマッパーのような魔法に依存してはならないということです。何らかの魔法が起こっていない限り、完全に役に立たないクラスは、クラスをあまりよく考えていません。 「ビジネス価値」だけが優れたデザインの決定要因ではありません。

  • テストプロセスにオートマッパーを含めます。これはもはやユニットテストではないと言う人もいます。それは問題ではありません。単体テストはのみのテストではありません。

  • 特にテスト用にオートマッパーの機能を提供するものを実装します。プロパティ名と値を含むディクショナリからオブジェクトを生成するためにリフレクションを使用する小さなユーティリティを簡単に作成できます。

また、この質問と回答を見てください: テスト用にプライベートなものを内部/パブリックにするか、PrivateObjectのようなある種のハックを使用しますか?

8
Mike Nakis

このようなことをテストでリフレクションを使用することをためらわない。

間違った理由でコードを変更するため、モックを仮想化するのは嫌いです。

私はオートマッパーを知りませんが、テストに含めることは良い考えであると@Mikeに同意します。単体テスト/統合テストの区別はあまり興味深いものではありません。確かに、テストスイートが大きく遅くなる場合は、すべてのテストの賢明なサブセットのみを最高の頻度で実行するために、フィルタリングと分類を行う必要があります。

リフレクションを使用したサンプルハック、nameof()を使用した場合のパフォーマンスは向上しますが、型を失うことになります。

public static class TestExtensions
{
    public static void SetProperty<TSource, TProperty>(
        this TSource source,
        Expression<Func<TSource, TProperty>> prop,
        TProperty value)
    {
        var propertyInfo = (PropertyInfo)((MemberExpression)prop.Body).Member;
        propertyInfo.SetValue(source, value);
    }
}
3
Johan Larsson

ユニットテストの目的で、Microsoft Fakes、TypeMock、JustMockなどのモックフレームワークを使用して、プライベートメンバーのモックをサポートします。

Smocks(利用可能な@nugetパッケージ)もご覧ください。 Smocksの制限は、プライベートメンバーへのアクセスを提供しないことです。しかし、静的メンバーと非仮想メンバーをモックする機能があります。また、無料でご利用いただけます。

もう1つの最も簡単な方法は、PrivateObject/PrivateTypeを使用することです。

0
Karthik V