我在思考是否应该开始更多地使用 internal
访问修饰符。
我知道,如果我们使用 internal
并设置程序集变量 InternalsVisibleTo
,那么我们就可以从测试项目中测试不想声明为公共的函数。
这让我觉得我应该总是使用 internal
,因为至少每个项目(应该?)都有自己的测试项目。
为什么不能这样做呢?何时应该使用 private
?
我在思考是否应该开始更多地使用 internal
访问修饰符。
我知道,如果我们使用 internal
并设置程序集变量 InternalsVisibleTo
,那么我们就可以从测试项目中测试不想声明为公共的函数。
这让我觉得我应该总是使用 internal
,因为至少每个项目(应该?)都有自己的测试项目。
为什么不能这样做呢?何时应该使用 private
?
需要测试内部类,并且有一个程序集属性:
using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo("MyTests")]
将以下内容加入项目信息文件中,例如 Properties\AssemblyInfo.cs
,适用于被测试的项目。在这种情况下,“MyTests”是测试项目。
#if DEBUG
和 #endif
包围起来,这样只有在调试版本中才能启用该选项。 - The Real Edward Cullen补充Eric的回答,您也可以在csproj
文件中进行配置:
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>MyTests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
或者如果你有一个测试项目来测试每个项目,那么你可以在Directory.Build.props
文件中做类似于这样的事情:
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>$(MSBuildProjectName).Test</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
参见:https://dev59.com/GVgQ5IYBdhLWcg3wazMi#49978185
示例:https://github.com/gldraphael/evlog/blob/master/Directory.Build.props#L5-L12
AssemblyInfo
文件要干净得多。 - Rickless.NET Framework 4.8
并没有起到作用。但是根据 @EricSchaefer 的答案,使用 AssemblyInfo.cs
是有效的。 - JohnBcsproj
文件中使用这种语法。 <ItemGroup>
<InternalsVisibleTo Include="MyProject.Tests" />
</ItemGroup>
我正在使用 .NET Core 3.1.101
,对我有效的 .csproj
修改如下:
<PropertyGroup>
<!-- Explicitly generate Assembly Info -->
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
<_Parameter1>MyProject.Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
默认情况下保持私有。如果成员不应该超出该类型,即使在同一项目中也不应该超出该类型,这样可以更安全、更整洁-当使用对象时,清楚哪些方法是可以使用的。
话虽如此,我认为有时将自然私有方法设置为内部方法以进行测试目的是合理的。我更喜欢这种方式,而不是使用反射,后者难以重构。
需要考虑的一件事可能是添加“ForTest”后缀:
internal void DoThisForTest(string name)
{
DoThis(name);
}
private void DoThis(string name)
{
// Real implementation
}
那么当你在同一项目中使用该类时,显然(现在和将来)你不应该真正使用这个方法-它只是为了测试目的而存在。 这有点hacky,并不是我自己做的事情,但至少值得考虑。
ForTest
标记的方法是明显错误的,而如果你只是将该方法设为internal,则看起来使用它就像是可行的。 - Jon Skeet你可以使用private,并且可以使用反射调用私有方法。如果你使用Visual Studio Team Suite,它具有一些很好的功能,可以为您生成代理来调用私有方法。这里有一篇代码项目文章,演示了如何自己完成单元测试私有和受保护的方法:
http://www.codeproject.com/KB/cs/testnonpublicmembers.aspx
在选择访问修饰符时,我的一般经验法则是从private开始,按需升级。这样,你将仅暴露出真正需要的类内部细节,有助于隐藏实现细节,使其得以保密。
对于.NET Core,您可以将属性添加到命名空间中,例如: [assembly: InternalsVisibleTo("MyUnitTestsAssemblyName")]. 类似这样的例子
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Applications.ExampleApp.Tests")]
namespace Applications.ExampleApp
internal sealed class ASampleClass : IDisposable
{
private const string ApiVersionPath = @"api/v1/";
......
......
......
}
}
using ...
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("MyAssembly.Unit.Tests")]
namespace
{
...
InternalsVisibleTo.cs
文件添加到项目的根文件夹中,即.csproj
文件所在的位置。
InternalsVisibleTo.cs
文件的内容应如下:using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("AssemblyName.WhichNeedAccess.Example.UnitTests")]
System.Diagnostics.Debug.Assert()
来避免对内部方法进行单元测试的需要。 - Mike Marynowski