通过System.Reflection访问内部成员?

24

我试图对一个有许多内部函数的类进行单元测试。显然,这些函数也需要测试,但我的测试项目是独立的,主要是因为它涵盖了许多小的相关项目。到目前为止我所做的是:

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并且真的很喜欢它,但如何使用它实现相同的功能呢?

5个回答

32

使用InternalsVisibleTo属性来将程序集的内部成员授权给单元测试程序集会更加合适。

以下链接提供了一些有用的额外信息和演示:

实际上,Internal和Protected在.NET反射API中没有被识别。以下是MSDN的引用:

C#关键字Protected和Internal在IL中没有意义,也不在Reflection API中使用。IL中对应的术语是Family和Assembly。要使用Reflection标识内部方法,请使用IsAssembly属性。要识别受保护的内部方法,请使用IsFamilyOrAssembly


我同意使用InternalsVisibleTo,但还是谢谢你的回答 :) - Matthew Scharley
没问题,即使在你的特定用例中采用不同的方法更合适,有一个实际的解释也是很好的。 - Eric Schoonover
2
只是提醒一下,这个答案中链接的页面是我的,我的URL已经更改。这就是为什么你可能会得到404错误。请尝试使用此更新的链接http://jason.whitehorn.ws/2007/11/09/The-Wonders-Of-InternalsVisibleTo.aspx。 - Jason Whitehorn

6

我认为你需要问自己是否需要为私有方法编写单元测试?如果你已经为公共方法编写了单元测试,并且代码覆盖率“合理”,那么不是已经测试了需要调用的任何私有方法吗?

将测试与私有方法绑定会使测试更加脆弱。你应该能够更改任何私有方法的实现而不破坏任何测试。

参考资料:

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 Link


我测试所有的内部方法。过度测试可能会导致一点浪费时间,但这是唯一可能发生的事情。 - Eric Schoonover
@spoon16:但如果没有公共方法调用它们,那有什么意义呢? - Mitch Wheat
重点是有某些东西在调用它们,而你正在测试这个东西是否能够期望正确的事情。在我的特定情况下,我正在尝试对一些基于事件的东西进行单元测试,因此我需要访问内部的PerformEvent()调用以手动触发事件。 - Matthew Scharley
基本上,如果那个内部方法被多个公开可访问的成员共享或调用,那么如果这些公共成员的测试开始失败,它可以帮助我更快地识别问题的来源。 - Eric Schoonover
这不是“太难”的问题,而是如果你有更多的测试覆盖率,它会变得更容易。 - Eric Schoonover
显示剩余4条评论

6

您的代码只显示字段-因此,我希望它不会显示任何内部成员,因为在我看来,字段始终应该是私有的。(可能除了常量。)

ButtonedForm.TitleButton实际上是否有任何非私有字段?如果您正在尝试查找内部方法,那么显然需要调用GetMethods(或GetMembers)才能访问它们。

正如其他人所建议的那样,InternalsVisibleTo非常适用于测试(几乎仅用于测试!)。至于您是否应该测试内部方法-我确实发现这很有用。我不认为单元测试是专门黑盒测试。通常,当您知道公共功能是使用连接在简单方式中的一些内部方法实现时,更容易对每个内部方法进行彻底的测试,并对公共方法进行一些“伪集成”测试。


你说得对,我本来应该一开始就调用GetMethods()的。明天再得到更多的投票后加上+1吧。我对整个反射的东西还不是很熟悉,能告诉我一下吗?:D 我正在制作一个小型脚本语言,我想这会让我真正了解反射... - Matthew Scharley

6

在您的主项目中添加 InternalsVisibleTo 程序集级别属性,并将程序集名称设置为测试项目,这样可以使内部成员可见。

例如,在任何类外部添加以下内容:

[assembly: InternalsVisibleTo("AssemblyB")]

或者更具体地定位:
[assembly:InternalsVisibleTo("AssemblyB, PublicKey=32ab4ba45e0a69a1")]

请注意,如果您的应用程序程序集具有强名称,那么您的测试程序集也需要具有强名称。

1

在我的情况下,使用InternalsVisible的理由是合理的。我们购买了一个图表控件的源代码。我们已经找到了需要对该源代码进行一些修改并编译我们自己的版本的地方。现在为了确保我们没有破坏任何东西,有一些单元测试我需要编写,需要访问一些内部字段。

这是一个完美的情况,InternalsVisible很有意义。

我想知道,如果您没有访问源代码,该怎么办?如何访问内部字段?.Net Reflector可以看到该代码,但我想它只是查看IL。


正如其他人提到的那样,在IL中,内部结构被称为程序集。您可以使用System.Reflection来访问这些程序集变量。 - Matthew Scharley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接