もくじ
やりたいこと
作ったクラスやメソッドのUnitTestをしたいが、privateやinternalにしているメソッドはUnitTestプロジェクトのコードから見えないので、普通にはテストできなかった。どうにかしてテストしたい。
やり方
PrivateObjectやPrivateTypeクラスを使う。
private、internalメソッドを外から呼ぶ
PrivateObjectクラスのInvokeメソッドを使う。
- テスト対象クラスをnewする
- それを引数にして、PrivateObjectクラスをnewする
- そのインスタンスで、PrivateObjectのInvokeメソッドを呼ぶ
- Invokeの第一引数には対象のprivateのメソッド名を渡す
- Invokeの第二引数以降にはそのメソッドに渡す引数を渡す
var cls1 = new Class1();
var pbObj = new PrivateObject(cls1);
ret = (string)pbObj.Invoke("AddPrivate", 1, 2);
private static、internal staticメソッドを外から呼ぶ
PrivateTypeクラスのInvokeStaticメソッドを使う。
- テスト対象のクラスのtypeを引数にして、PrivateTypeをnewする
- そのインスタンスで、PrivateTypeのInvokeStaticメソッドを呼ぶ
- InvokeStaticの第一引数には対象のprivateのメソッド名を渡す
- InvokeStaticの第二引数以降にはそのメソッドに渡す引数を渡す
PrivateType privateType = new PrivateType(typeof(Class1));
ret = (string)privateType.InvokeStatic("AddPrivateStatic", 1, 2);
子クラスから見た親クラスのprivateメソッドを外から呼ぶ
PrivateObjectクラスのInvokeメソッドを使う。
その際、PrivateObjectをnewするときの引数を変える。(詳細はサンプル参照)
- テスト対象クラス(子クラス)をnewする
- それを第一引数、第二引数に親クラスのtypeを引数にしたPrivateTypeをnewしたものを渡して、PrivateObjectクラスをnewする
- そのインスタンスで、PrivateObjectのInvokeメソッドを呼ぶ
var clssub = new Class1Sub();
var pbObjSub = new PrivateObject(clssub, new PrivateType(typeof(Class1)));
ret = (string)pbObjSub.Invoke("AddPrivate", 1, 2);
サンプルコード
テストしたいdllを呼んで、UnitTestを行うためのプロジェクトのコード。
UnitTest1.cs
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ClassLibrary1;
namespace UnitTestProject1
{
// 参考:https://www.gesource.jp/weblog/?p=7742
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var ret = "";
var cls1 = new Class1();
// publicなメソッドのテスト
ret = cls1.AddPublic(1, 2);
ret = Class1.AddPublicStatic(1, 2);
// private、internalなメソッドのテスト
var pbObj = new PrivateObject(cls1);
ret = (string)pbObj.Invoke("AddPrivate", 1, 2);
ret = (string)pbObj.Invoke("AddInternal", 1, 2);
// private static、internal staticなメソッドのテスト
PrivateType privateType = new PrivateType(typeof(Class1));
ret = (string)privateType.InvokeStatic("AddPrivateStatic", 1, 2);
ret = (string)privateType.InvokeStatic("AddInternalStatic", 1, 2);
// 子クラスから見た親クラスのprivateメソッドをテスト
var clssub = new Class1Sub();
var pbObjSub = new PrivateObject(clssub, new PrivateType(typeof(Class1)));
ret = (string)pbObjSub.Invoke("AddPrivate", 1, 2);
ret = (string)pbObjSub.Invoke("AddInternal", 1, 2);
// 子クラスから見た親クラスのprivate staticメソッドは、
// 親クラスのprivate staticテストと同じ。
}
}
}
UnitTestから呼ぶ実験用dllのコード。
public、private、internalなメソッドと、その3つをstaticにしたメソッドを含む。
Class1.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
namespace ClassLibrary1
{
public class Class1
{
public string AddPublic(int val1, int val2)
{
return MethodBase.GetCurrentMethod().Name + " " + (val1 + val2).ToString();
}
internal string AddInternal(int val1, int val2)
{
return MethodBase.GetCurrentMethod().Name + " " + (val1 + val2).ToString();
}
private string AddPrivate(int val1, int val2)
{
return MethodBase.GetCurrentMethod().Name + " " + (val1 + val2).ToString();
}
public static string AddPublicStatic(int val1, int val2)
{
return MethodBase.GetCurrentMethod().Name + " " + (val1 + val2).ToString();
}
internal static string AddInternalStatic(int val1, int val2)
{
return MethodBase.GetCurrentMethod().Name + " " + (val1 + val2).ToString();
}
private static string AddPrivateStatic(int val1, int val2)
{
return MethodBase.GetCurrentMethod().Name + " " + (val1 + val2).ToString();
}
}
public class Class1Sub : Class1
{
}
}
コード
参考
MSTestでprivateメソッドをテストする
ほぼこちらを参考にさせていただいています。ありがとうございます。
https://www.gesource.jp/weblog/?p=7742