进行单元测试时的C#“内部”访问修饰符

时间:2008-12-11 01:20:30

标签: c# .net unit-testing tdd

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

9 个答案:

答案 0 :(得分:1054)

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

using System.Runtime.CompilerServices;

[assembly:InternalsVisibleTo("MyTests")]

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

答案 1 :(得分:112)

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

文档: PrivateTypePrivateObject

答案 2 :(得分:10)

您也可以使用私有,您可以使用反射调用私有方法。如果您使用的是Visual Studio Team Suite,它有一些很好的功能,可以生成一个代理来为您调用私有方法。这是一篇代码项目文章,演示了如何自己完成工作以对私有和受保护方法进行单元测试:

http://www.codeproject.com/KB/cs/testnonpublicmembers.aspx

就您应该使用的访问修饰符而言,我的一般经验法则是私有,并根据需要升级。这样,您将尽可能少地暴露您的类的内部细节,并且有助于保持实现细节隐藏,就像它们应该的那样。

答案 3 :(得分:10)

默认情况下继续使用私有。如果成员不应暴露在该类型之外,则不应暴露在该类型之外,即使是在同一项目中也是如此。这样可以使事情更加安全和整洁 - 当您使用该物体时,您可以使用哪种方法更清晰。

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

要考虑的一件事可能是“ForTest”后缀:

internal void DoThisForTest(string name)
{
    DoThis(name);
}

private void DoThis(string name)
{
    // Real implementation
}

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

答案 4 :(得分:6)

我正在使用Dotnet 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>

希望这对外面的人有帮助!

答案 5 :(得分:1)

除了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://stackoverflow.com/a/49978185/1678053

答案 6 :(得分:1)

对于 .NET 核心,您可以将属性添加到命名空间中 [装配: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/";
        ......
        ......
        ......
        }
    }

答案 7 :(得分:0)

在dotnet Core 2.2中,将此行添加到Program.cs

使用...

使用System.Runtime.CompilerServices;

[assembly:InternalsVisibleTo(“ MyAssembly.Unit.Tests”)]

命名空间 { ...

答案 8 :(得分:0)

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

InternalsVisibleTo.cs 的内容应如下

using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("AssemblyName.WhichNeedAccess.Example.UnitTests")]