使用InternalsVisibleTo来编写单元测试代码是否被认为是不良实践?

40

在框架的 AssemblyInfo.cs 中的示例代码:

[assembly: System.Runtime.CompilerServices.InternalsVisibleTo
                          ("Test.Company.Department.Core")]

这是一种不好的做法吗?

6个回答

45

不,这并不被认为是不良做法。如果你想测试的类在你的程序集中是有充分理由是内部类,那么没有其他方法。不测试它们会更糟糕。


1
如果您的类仅为内部类,则无法使用它们。您可能会公开使用内部类的公共API。然后,通过公共API测试内部类应该是可能的(但可能更或少困难)。通过公共API进行测试更可取,因为它使重构内部API更容易。 - Rickard
16
@Rickard: 我非常不同意:公共API的目的是能够轻松地被其他人使用。通过公共API测试所有内部类型的功能至少是繁琐的。在每个不太小的API接口后面可能会有一个具有复杂交互和分支的对象图。测试公共API更像是一个集成测试。 - Daniel Hilgarth
那么你觉得测试私有成员和方法也没问题吗? - Rickard
4
不行,区别在于大小。你不能将一个私有方法与一个内部类或者整个对象图进行比较。 - Daniel Hilgarth
好的,我同意。我的观点可能过于笼统,即InternalsVisibleTo不应该是您的首选,而是在有意义的情况下使用它,例如API的大小很重要。 - Rickard
4
我同意这种观点。我之所以认为这样做没问题是基于简单实用主义的理由:如果仅使用公共 API 时无法轻松编写合理的有针对性的测试,可以使用 InternalsVisibleTo。否则,请使用公共 API。 - Daniel Hilgarth

32

就我个人而言,我认为这样做是可以的。我从来没有遵循“仅测试公共方法”的教条。我认为黑盒测试也是有好处的,但白盒测试可以让你使用更简单的测试来测试更多的场景,特别是当你的API比较“厚重”且公共方法实际上需要完成很多工作时。

同样,在一个完全封装的项目中,您可能会有几种只有内部方法的内部类型。现在假设这些类型将产生公共影响,因此您可以通过公共类型进行所有测试。但是,如果您使用InternalsVisibleTo,那么您可以使用非常简单的测试来测试某些东西,而不需要经过很多麻烦。


4

InternalsVisibleTo 可以在您不想公开的情况下测试 API 的子部分,这很有用。

然而,通过公共 API 进行测试更可取,因为它使重构内部 API 更加容易。使用 InternalsVisibleTo 要谨慎,只在适当的时候使用,例如 API 的规模相当大。


"...它使重构内部API更容易":一个具体要考虑的点,谢谢。 - Ishmaeel

2

我认为这样做是完全合理的。

我发现这对于依赖注入非常有用。如果我有一个带有几个依赖项的构造函数的类,以允许进行单元测试,我经常将其标记为内部,并在我的单元测试项目中公开它。然后我会有一个公共(无参数,或至少参数更少)构造函数。这使得公共接口保持清洁,同时仍允许进行可测试的代码。


听起来不太好,测试代码使用与生产代码不同的构造函数。 - Shadow

1
我认为这是一种不好的做法,因为如果您已经使用了SOLID原则,那么您就不应该使用"InternalsVisibleTo"。但是在“现实世界”中,您会得到各种各样的代码...所以务实的方法是最好的。
此外,在使用混淆的情况下,“InternalsVisibleTo”并不理想。混淆器往往会混淆“内部”内容。因此,任何试图引用混淆的dll的内部的外部dll都将失败。您可以配置混淆器以忽略外部引用的项目,但这将降低任何混淆器的效果。
在我看来,尽量避免使用"InternalsVisibleTo"。但是,如果您必须使用它,则代码结构存在问题(这种情况很常见)。

1

不是的,当使用正确时,因为在某些情况下它是必要的。例如,您有一个单元测试A需要测试程序集B中使用一些内部类型的公共成员。单元测试需要这个类型,因此您必须使用InternalsVisibleTo

它还可以用于保护代码。例如,激活程序集。您可能只希望解决方案中的一个模块访问您的激活程序集,并防止任何人添加对其的引用并调用方法。您可以将类型和成员设置为内部,仅向具有公钥标记的已签名程序集公开它们,从而使其对世界其他地方隐藏。


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