C# “C”;“内部”;进行单元测试时访问修改器

C# “C”;“内部”;进行单元测试时访问修改器,c#,.net,unit-testing,tdd,C#,.net,Unit Testing,Tdd,我是单元测试新手,我正在试图弄清楚是否应该开始更多地使用内部访问修饰符。我知道如果我们使用internal并将程序集变量internalsvisible设置为,我们可以测试我们不想从测试项目中声明为公共的函数。这让我觉得我应该总是使用内部,因为至少每个项目(应该?)都有自己的测试项目。你们能告诉我为什么我不该这么做吗?什么时候应该使用private?您也可以使用private,并且可以通过反射调用private方法。如果您使用的是VisualStudioTeamSuite,它有一些很好的功能,可

我是单元测试新手,我正在试图弄清楚是否应该开始更多地使用
内部
访问修饰符。我知道如果我们使用
internal
并将程序集变量
internalsvisible设置为
,我们可以测试我们不想从测试项目中声明为公共的函数。这让我觉得我应该总是使用
内部
,因为至少每个项目(应该?)都有自己的测试项目。你们能告诉我为什么我不该这么做吗?什么时候应该使用private?

您也可以使用private,并且可以通过反射调用private方法。如果您使用的是VisualStudioTeamSuite,它有一些很好的功能,可以生成一个代理来为您调用私有方法。下面是一篇代码项目文章,演示了如何自己进行单元测试私有和受保护方法:


关于应该使用哪种访问修饰符,我的一般经验法则是从private开始,并根据需要升级。这样,您将尽可能少地公开真正需要的类的内部细节,并有助于保持实现细节的隐藏,因为它们应该是隐藏的。

如果您想测试私有方法,查看
Microsoft.VisualStudio.TestTools.UnitTesting
命名空间中的
PrivateObject
PrivateType
。它们围绕必要的反射代码提供了易于使用的包装

文件: ,


对于VS2017和2019,您可以通过下载MSTest.TestFramework nuget找到这些默认设置。如果一个成员不应该暴露在该类型之外,那么它就不应该暴露在该类型之外,甚至在同一个项目中。这可以让事情更安全、更整洁——当你使用对象时,你可以更清楚地知道应该使用哪些方法

话虽如此,我认为有时出于测试目的将自然私有方法内部化是合理的。我更喜欢使用反射,这是不友好的重构

一个要考虑的事情可能是一个“考验”后缀:


然后,当您在同一个项目中使用该类时,很明显(现在和将来),您不应该真正使用该方法-它只是用于测试目的。这有点粗糙,不是我自己做的,但至少值得考虑。

内部类需要测试,并且有一个assemby属性:

using System.Runtime.CompilerServices;

[assembly:InternalsVisibleTo("MyTests")]

将其添加到项目信息文件中,例如
Properties\AssemblyInfo.cs

添加到Eric的答案中,您还可以在
csproj
文件中配置:




示例:

我正在使用
.NET Core 3.1.101
,对我有效的
.csproj
添加内容包括:


真的
我的项目。测试

在.NET Core 2.2中,将此行添加到程序中。cs:

使用。。。
使用System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo(“MyAssembly.Unit.Tests”)]
名称空间
{
...

InternalsVisibleTo.cs
文件添加到项目的根文件夹中,其中存在
.csproj
文件

InternalsVisibleTo.cs
的内容如下

使用System.Runtime.CompilerServices;
[程序集:InternalsVisibleTo(“AssemblyName.WhichNeedAccess.Example.UnitTests”)]

对于.NET core,您可以将属性添加到命名空间中,如下所示: [程序集:InternalsVisibleTo(“MyUnitTestsAssemblyName”)]。 e、 差不多

using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Applications.ExampleApp.Tests")]
namespace Applications.ExampleApp
 internal sealed class ASampleClass : IDisposable
    {
        private const string ApiVersionPath = @"api/v1/";
        ......
        ......
        ......
        }
    }

如果方法是内部的,这不排除在测试程序集中使用它吗?我偶尔会使用
ForTest
方法,但我总是觉得它非常难看(添加的代码在生产业务逻辑方面没有提供任何实际价值)。通常我发现我不得不使用这种方法,因为设计很不幸(即,必须在测试之间重置单例实例)试图否决这一点-这一攻击与简单地将类设置为内部而不是私有有什么区别?好吧,至少在编译条件下是这样。然后它变得非常混乱。@Cadbroke:你是说将方法设置为内部而不是私有吗?区别是很明显,你真的希望它是私有的。有没有在生产代码库中使用de调用带有
ForTest
的方法显然是错误的,但是如果您只是将该方法设置为内部,则看起来可以使用它。@Cadbloce:您可以在发布版本中排除单个方法,就像在同一个文件中使用分部类一样容易。如果您这样做,它建议您没有针对发布版本运行测试,这听起来是个坏主意。请将其添加到正在测试的项目中(例如,在Properties\AssemblyInfo.cs中)。“MyTests”将是测试程序集。这应该是公认的答案。我不知道你们的情况,但当测试“太远”时从他们正在测试的代码来看,我倾向于感到紧张。我完全赞成避免测试任何标记为
private
的东西,但是太多的
private
东西很可能指向一个
内部的
类,这个类很难被提取出来。TDD或无TDD,我宁愿有更多的测试来测试大量的代码,而不是很少的测试不要使用同样数量的代码。避免测试
内部的
东西并不能完全帮助达到一个好的比率。@DerickBailey和dantao之间在内部和私有的语义差异以及测试内部组件的需要方面有很大的不同。值得一读。如果调试
#endif
块将仅在调试版本中启用此选项。这是正确的答案。任何说只有公共方法才应该进行单元测试的答案都忽略了单元测试的要点,并提供了借口。功能测试是面向黑盒的。单元测试是面向白盒的。它们应该测试“单元”功能性
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Applications.ExampleApp.Tests")]
namespace Applications.ExampleApp
 internal sealed class ASampleClass : IDisposable
    {
        private const string ApiVersionPath = @"api/v1/";
        ......
        ......
        ......
        }
    }