C#のユニットテストでプライベートなフィールドにアクセスする

C#でMSTestのテストプロジェクトを使用してテストする際、
テスト対象のクラスのプライベートフィールドの値を変えたいことがあります。

たとえば、下記のようなクラスがあったとします。

public class Sample
{
    private int a = 0;

    public bool OK { get { return this.a > 50; } }
}

OKプロパティはプライベートフィールドaが50より大きい場合にtrueとなります。
下記のようなテストメソッドで、OKの戻り値の確認をしたい場合があります。

[TestMethod]
public void TestMethod1()
{
    Sample sample = new Sample();
    // ここでsample.aを50より大きい値にしたい
    Assert.IsTrue(sample.OK);
}

.NET Frameworkのプロジェクトであれば下記のようにPrivateObjectが使用できます。

[TestMethod]
public void TestMethod1()
{
    Sample sample = new Sample();
    PrivateObject privateObject = new PrivateObject(sample);
    privateObject.SetFieldOrProperty("a", 51);
    Assert.IsTrue(sample.OK);
}

PrivateObjectのコンストラクタにインスタンスを渡します。
そしてPrivateObjectのSetFieldOrPropertyメソッドでフィールド名と値を指定すると設定ができます。

ただ、このPrivateObjectは.NET Frameworkでないと使用できないため、.NET8などのプロジェクトでは使用できません。
そこで、別の方法、リフレクションを使用する方法です。

[TestMethod]
public void TestMethod2()
{
    Sample sample = new Sample();
    FieldInfo fieldInfo = sample.GetType().GetField("a", BindingFlags.NonPublic | BindingFlags.Instance);
    fieldInfo.SetValue(sample, 51);
    Assert.IsTrue(sample.OK);
}

インスタンスのTypeからフィールド名指定でField情報を取得します。
その際はNonPublicやInstanceといったフラグでプライベートフィールドであることを指定します。
一致するものがあればFieldInfoが返り、なければnullが返ります。
取得できれば、そのSetValueメソッドに、インスタンスと設定したい値を渡してやると設定できます。

スポンサーリンク