通过System.Reflection访问内部成员?
我正在尝试对具有许多内部函数的类进行unit testing。 这些显然也需要测试,但我的测试项目是独立的,主要是因为它涵盖了许多小的相关项目。 到目前为止我所拥有的是:
FieldInfo[] _fields = typeof(ButtonedForm.TitleButton).GetFields( BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); Console.WriteLine("{0} fields:", _fields.Length); foreach (FieldInfo fi in _fields) { Console.WriteLine(fi.Name); }
这很好地吐出了所有的私人成员,但仍然没有显示内部。 我知道这是可能的,因为当我搞乱Visual Studio可以生成的自动生成的测试时,它询问了如何处理显示Test项目的内部结构。 好吧,现在我正在使用NUnit而且非常喜欢它,但是我怎么能用它来实现同样的目的呢?
使用InternalsVisibleTo
属性来授予对unit testing程序集的程序集内部成员的访问权限更为合适。
这是一个链接,其中包含一些有用的附加信息和演练:
- InternalsVisible的奇迹
要实际回答您的问题… .NET Reflection API中无法识别内部和受保护。 以下是MSDN的报价:
C#关键字protected和internal在IL中没有任何意义,并且不在Reflection API中使用。 IL中的相应术语是Family和Assembly。 要使用Reflection标识内部方法,请使用IsAssembly属性。 要标识受保护的内部方法,请使用IsFamilyOrAssembly 。
将InternalsVisibleTo程序集级别属性添加到主项目中,使用程序集名称为thre test项目应该使内部成员可见。
例如,在任何类之外的程序集中添加以下内容:
[assembly: InternalsVisibleTo("AssemblyB")]
或者针对更具体的定位:
[assembly:InternalsVisibleTo("AssemblyB, PublicKey=32ab4ba45e0a69a1")]
请注意,如果您的应用程序集具有强名称,那么您的测试程序集也需要具有强名称。
我想你需要问一下你是否应该为私有方法编写unit testing? 如果您为公共方法编写unit testing,并且具有“合理的”代码覆盖率,那么您是否已经在测试任何需要调用的私有方法?
将测试绑定到私有方法将使测试更加脆弱。 您应该能够在不破坏任何测试的情况下更改任何私有方法的实现。
参考文献:
http://weblogs.asp.net/tgraham/archive/2003/12/31/46984.aspx http://richardsbraindump.blogspot.com/2008/08/should-i-unit-test-private-methods.html http://junit.sourceforge.net/doc/faq/faq.htm#tests_11 http://geekswithblogs.net/geekusconlivus/archive/2006/07/13/85088.aspx
您的代码只显示字段 – 所以我希望它不会显示任何内部成员,因为字段应始终是私有IMO。 (可能的常数除外。)
ButtonedForm.TitleButton实际上是否有任何非私有字段? 如果您正在尝试查找内部方法,那么显然您需要调用GetMethods
(或GetMembers
)来获取它们。
正如其他人所建议的那样, InternalsVisibleTo
非常便于测试(并且几乎仅用于测试!)。 至于你是否应该测试内部方法 – 我当然觉得能够这样做很有用。 我不认为unit testing是专门的黑盒测试。 通常当您知道使用以简单方式连接的一些内部方法实现公共function时,更容易对每个内部方法进行全面测试,并对公共方法进行一些“伪集成”测试。
在我的情况下,使用InternalsVisible的理由是正确的。 我们购买了Chart Control的源代码。 我们已经找到了我们需要对源代码控件进行一些修改并编译我们自己的版本的地方。 现在为了确保我们没有破坏任何东西,我需要编写一些需要访问某些内部字段的unit testing。
这是InternalsVisible有意义的完美案例。
不过我想知道,如果你没有访问源代码,你会怎么做? 你怎么能进入内部领域? .Net Reflector可以看到该代码,但我想它只是在看IL。