最近在做測試時,要進行 private method 的測試,由於保護層級的關係,無法直接測試,這邊記錄如何用其他方式達到 private method 的測試
為了測試,在某些 class 裡的 method 本來是定義為 private or protected 的方法,網路上有些方法是會教你改成 internal 的方式,讓你可以在 unit test 比較容易測試
my.Person.program.Run();
namespace my.Person
{
using lib.Person;
public static class program
{
public static void Run()
{
var p = new Person()
{
id =1
};
//會失敗
Console.WriteLine( p.GetDBId());
}
}
}
namespace lib.Person
{
public class Person
{
public int id {set;get;}
//假設 db id 是由 id欄位去運算得知,不適合給外部物件知道的資訊
private int GetDBId()
{
return id*10;
}
}
}
如果是用 internal 的方式,就會長成這樣,但實際上這個方法還是不適合暴露出去
public class Person
{
public int id {set;get;}
//假設 db id 是由 id欄位去運算得知,不適合給外部物件知道的資訊
internal int GetDBId()
{
return id*10;
}
}
而為了讓 lib.Person 可以讓 my.Person 可以存取,還得放上一個檔案騙編譯器
[assembly: System.Runtime.CompilerServices.InternalsVisibleToAttribute("my.Person")]
namespace cache
{
internal class VisibleProject
{
}
}
而實質上,其實不需要把 private 的方法改成 internal,也可以在測試達到一樣的目地,前提是我們真的有必要去測 private 的方法
否則其他 public 的 method 應該也會用到 private 的方法,應當是去測公開的方法就好
比如說像 private method 可能是由事件所觸發,比方說 rabbit mq 這類型的
另一個測試的方法就是用反射的方法取到 method 後,再用 invoke 的方式去執行
my.Person.program.Run();
namespace my.Person
{
using lib.Person;
public static class program
{
public static void Run()
{
var p = new Person()
{
id =1
};
InvokePrivateMehtod(p, "GetDBId", null );
}
private static void InvokePrivateMehtod<T>(T instance, string methodName, object[] parameters)
{
MethodInfo methodInfo = typeof(T).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
if (parameters == null)
Console.WriteLine( methodInfo.Invoke(instance, null));
else
Console.WriteLine( methodInfo.Invoke(instance, parameters));
}
}
}
namespace lib.Person
{
public class Person
{
public int id {set;get;}
//假設 db id 是由 id欄位去運算得知,不適合給外部物件知道的資訊
private int GetDBId()
{
return id*10;
}
}
}
至於 .net framework 的話,可以使用 PrivateObject 這種寫法,然而 .net core 已經棄用這個物件方法了
但底層方法看起來應當是雷同的