private、internalなメソッドのUnitTest(.NET6版)

もくじ

目次(WPF/xaml/C#/C++関連メモ) - tera1707’s blog

やりたいこと

以前、.NetFrameworkでのUnitTestをつくるときに、privateやinternalなメソッドを外から呼ぶ方法を調べたが、.NET6で同じことをしようとすると、PrivateObjectクラスが使えなくなっていた。

.NET6でもprivateなメソッドをUnitTestしたいので、外から呼ぶやり方を調べたい。

やりかた

リフレクション(Reflection)を使う。

サンプル(privateなインスタンスメソッド)

具体的には、下記のようなコードを書く。

呼ばれる側dllのコード

namespace ClassLibrary1
{
    public class MyClass1
    {
        private int MyMethod() => 321;
    }
}

呼ぶ側のコード

    // exeを呼び出す
    var asm2 = Assembly.LoadFrom(@".\ClassLibrary1.dll");
    // exe内のクラスを呼び出す
    var type = asm2?.GetType("ClassLibrary1.MyClass1");
    // そのクラスをインスタンス化する
    var obj = Activator.CreateInstance(type) as ClassLibrary1.MyClass1;
    // 名前を指定してメソッドを取得
    var method = type.GetMethod("MyMethod", BindingFlags.Instance | BindingFlags.NonPublic);
    // そのメソッドを、使うインスタンスを指定して実行
    var ret3 = method.Invoke(obj, null);

サンプル(privateなstaticメソッド)

GetMethod()に渡すBindingFlagsのフラグを、BindingFlags.Staticにして、method.Invoke()の第一引数に渡すobjectをnullにしてやると、Staticなメソッドも呼べる。
(BindingFlags.Staticにせずにstaticなメソッドを呼ぶと、GetMethodの戻り値がnullになる。フラグ指定を間違えるとそうなるっぽい)

呼ばれる側

namespace ClassLibrary1
{
    public class MyClass1
    {
        private static int MyStaticMethod() => 999;
    }
}

呼ぶ側

    var asm2 = Assembly.LoadFrom(@".\ClassLibrary1.dll");
    var type = asm2?.GetType("ClassLibrary1.MyClass1");
    var method = type.GetMethod("MyStaticMethod", BindingFlags.Static | BindingFlags.NonPublic);
    var ret3 = method.Invoke(null, null);//objはいらない

同じように、BindingFlags.NonPublicBindingFlags.Publicにしてやると、publicなメソッドもこのやり方で呼べる。

サンプル(引数があるメソッド)

引数のあるメソッドを呼ぶためには、method.Invoke()の第二引数に、呼ぶメソッドに渡す引数を入れてやる。

引数のあるメソッド

namespace ClassLibrary1
{
    public class MyClass1
    {
        private static int MyStaticMethod(string arg1, int arg2, double[] ds) => 999;
    }
}

呼ぶ方

    var asm2 = Assembly.LoadFrom(@".\ClassLibrary1.dll");
    var type = asm2?.GetType("ClassLibrary1.MyClass1");
    var method = type.GetMethod("MyStaticMethod", BindingFlags.Static | BindingFlags.NonPublic);

    double[] ds = new double[] { 1.0, 2.0, 3.0 };
    object[] args = { "abc", 1, ds };
    var ret3 = method?.Invoke(null, args);

method.Invoke()の第二引数には、
method?.Invoke(null, "abc", 1, ds) ではなく、

先にobject[] objs = { "abc", 1, ds };としてから
method?.Invoke(null, objs);とする必要がある。

参考

t-pirori.blogspot.com