web-dev-qa-db-ja.com

PrivateObjectを使用して、クラスとその親の両方のプライベートメンバーにアクセスするにはどうすればよいですか?

階層の一部であるクラスをテストしています。テスト対象のオブジェクトとそのオブジェクトへのアクセスを許可するPrivateObjectを使用してテストクラスを設定しています。親クラスのプライベートメンバーにアクセスしようとすると、例外が発生します。

これまでに見つけた唯一の回避策は、基本クラスを指定するPrivateTypePrivateObjectコンストラクターに渡すことですが、サブクラスのプライベートメンバーでは機能しません。

PrivateオブジェクトのGet *メソッドでバインドフラグパラメーターを使用するなどして、これを行う方法はありますか?

自動生成されたAccessorクラスを使用してみました(メインクラスで右クリックして、Create Private Accessor)。ただし、それはさらに悪いことです。私が読み取ることができるプロパティを示しますが、PrivateObjectと同じ例外をスローし、例外を修正するために使用できる他のオプション(バインディングフラグなど)はありません。

これが私のサンプルテストコードです。 PrivateObjectを作成して使用して両方のフィールドを取得する方法が欲しいのですが。

public class BaseClass
{
    private int one = 1;
}

public class SubClass : BaseClass
{
    private int two = 2;
}

[TestClass]
public class UnitTest1
{
    BindingFlags flags = BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;

    [TestMethod]
    public void TestMethod1()
    {
        SubClass test = new SubClass();
        PrivateObject priv = new PrivateObject(test);

        Assert.AreNotEqual<int>(0, (int)priv.GetFieldOrProperty("one", flags)); // System.MissingMethodException: Method 'PrivateObjectTester.SubClass.one' not found.
        Assert.AreNotEqual<int>(0, (int)priv.GetFieldOrProperty("two", flags));
    }

    [TestMethod]
    public void TestMethod2()
    {
        SubClass test = new SubClass();
        PrivateObject priv = new PrivateObject(test, new PrivateType(typeof(BaseClass)));

        Assert.AreNotEqual<int>(0, (int)priv.GetFieldOrProperty("one", flags));
        Assert.AreNotEqual<int>(0, (int)priv.GetFieldOrProperty("two", flags)); // System.MissingMethodException: Method 'PrivateObjectTester.BaseClass.two' not found.
    }
}
25
David Yaw

私は答えを見つけられなかったので、これは私がやったことです。クラスの階層のレベルごとにPrivateObjectsを作成しました。適切なテストケースを使用するテストケースを作成するときは注意が必要です。

public class BaseClass
{
    private int one = 1;
}

public class SubClass : BaseClass
{
    private int two = 2;
}

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod()
    {
        SubClass test = new SubClass();
        PrivateObject privSub = new PrivateObject(test, new PrivateType(typeof(SubClass)));
        PrivateObject privBase = new PrivateObject(test, new PrivateType(typeof(BaseClass)));

        Assert.AreNotEqual<int>(0, (int)privBase.GetFieldOrProperty("one"));
        Assert.AreNotEqual<int>(0, (int)privSub.GetFieldOrProperty("two"));
    }
}
34
David Yaw

これはおそらくあなたが望む答えではありません...しかし、最初に両方のクラスを1つのメソッドでテストするべきではありません。一度に1つのクラスのみをテストする必要があります。これを行う必要があると感じた場合は、コードにリファクタリングが必要だと思います。しかし、私はあなたの実際のコードの問題を知らないので、私は確かに言うことはできません

10
AYoung
// create an instance of class SearchPlanogramsBuilder:
SearchPlanogramsBuilder searchPlanogramBuilder = new SearchPlanogramsBuilder(); 

// executing the method BuildSearchParameters(return type is void) with input searchPlanoGramsFilters:
searchPlanogramBuilder.BuildSearchParameters(searchPlanoGramsFilters);

// create privateobject and pass instance created for the class:
PrivateObject helperobject1 = new PrivateObject(searchPlanogramBuilder);

// type cast exactly as parameter(which is private variable) in the method:
Collection<string> parameter = (Collection<string>)helperobject1.GetFieldOrProperty("parameters");
1
lokesh

同じことをしたかったので、この拡張メソッドを作成しました。今ではうまくいきます。私の最初のアイデアはあなたの投稿からです。ありがとうございました!

https://github.com/cactuaroid/PrivateObjectExtensions

基本的には、Type.GetFields()Type.GetProperties()によってメンバーの所有者を再帰的に検索し、メンバーにアクセスするための正しい型としてPrivateObject(またはPrivateType)を作成します。

1
cactuaroid

アンドレ・ペーナが書いたように。なぜ、サブクラスを通じてベースクラスのprivateメンバーをテストするのですか。サブクラスの通常のコードでこれらのメンバーにアクセスすることもできません。サブクラスからプロパティメンバーにアクセスするには、プロパティメンバーをprotectedにする必要があります。

次に、これらのメンバーをPrivateObjectでテストすることもできます。

1
MrCube

PrivateObjectは、継承の処理に関しては、「ダム」側に少しあります。残念ながら、そのメソッドは仮想ではないため、この動作を変更する簡単な方法はありません。基本的に2つのオプションがあります。制限付きで生きるか、継承されたメンバーを透過的に処理できる独自のプライベートアクセサーヘルパーを作成します。

1
Nicole Calinoiu

PrivateTypeを使用して目的のタイプを指定し、PrivateObjectの別のコンストラクターを使用します。

var test = new SubClass();
var privateType = new PrivateType(typeof(BaseClass));
var privateObject = new PrivateObject(test, privateType);
// privateObject.GetFieldOrProperty("one", flags)
1
DonnyTian