简体   繁体   English

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

[英]C# "internal" access modifier when doing unit testing

I'm new to unit testing and I'm trying to figure out if I should start using more of internal access modifier.我是单元测试的新手,我试图弄清楚是否应该开始使用更多的internal访问修饰符。 I know that if we use internal and set the assembly variable InternalsVisibleTo , we can test functions that we don't want to declare public from the testing project.我知道如果我们使用internal并设置程序集变量InternalsVisibleTo ,我们可以测试我们不想从测试项目中公开的函数。 This makes me think that I should just always use internal because at least each project (should?) have its own testing project.这让我觉得我应该总是使用internal因为至少每个项目(应该?)都有自己的测试项目。 Can you guys tell me why I shouldn't do this?你们能告诉我为什么我不应该这样做吗? When should I use private ?我什么时候应该使用private

Internal classes need to be tested and there is an assemby attribute:需要测试内部类,并且有一个组件属性:

using System.Runtime.CompilerServices;

[assembly:InternalsVisibleTo("MyTests")]

Add this to the project info file, eg Properties\\AssemblyInfo.cs .将此添加到项目信息文件中,例如Properties\\AssemblyInfo.cs

If you want to test private methods, have a look at PrivateObject and PrivateType in the Microsoft.VisualStudio.TestTools.UnitTesting namespace.如果要测试私有方法,请查看Microsoft.VisualStudio.TestTools.UnitTesting命名空间中的PrivateObjectPrivateType They offer easy to use wrappers around the necessary reflection code.它们围绕必要的反射代码提供易于使用的包装器。

Docs: PrivateType , PrivateObject文档: PrivateTypePrivateObject

For VS2017 & 2019, you can find these by downloading the MSTest.TestFramework nuget对于 VS2017 和 2019,您可以通过下载 MSTest.TestFramework nuget 找到这些

Adding to Eric's answer, you can also configure this in the csproj file:添加到 Eric 的答案中,您还可以在csproj文件中进行配置:

<ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
      <_Parameter1>MyTests</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

Or if you have one test project per project to be tested, you could do something like this in your Directory.Build.props file:或者,如果每个要测试的项目都有一个测试项目,则可以在Directory.Build.props文件中执行以下操作:

<ItemGroup>
    <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
      <_Parameter1>$(MSBuildProjectName).Test</_Parameter1>
    </AssemblyAttribute>
</ItemGroup>

See: https://stackoverflow.com/a/49978185/1678053参见: https : //stackoverflow.com/a/49978185/1678053
Example: https://github.com/gldraphael/evlog/blob/master/Directory.Build.props#L5-L12示例: https : //github.com/gldraphael/evlog/blob/master/Directory.Build.props#L5-L12

Keep using private by default.默认情况下继续使用私有。 If a member shouldn't be exposed beyond that type, it shouldn't be exposed beyond that type, even to within the same project.如果成员不应超出该类型公开,则不应超出该类型公开,即使在同一项目中也是如此。 This keeps things safer and tidier - when you're using the object, it's clearer which methods you're meant to be able to use.这让事情更安全、更整洁——当你使用对象时,你应该能够使用哪些方法会更清楚。

Having said that, I think it's reasonable to make naturally-private methods internal for test purposes sometimes.话虽如此,我认为有时出于测试目的将自然私有方法置于内部是合理的。 I prefer that to using reflection, which is refactoring-unfriendly.我更喜欢使用反射,这是重构不友好的。

One thing to consider might be a "ForTest" suffix:需要考虑的一件事可能是“ForTest”后缀:

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

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

Then when you're using the class within the same project, it's obvious (now and in the future) that you shouldn't really be using this method - it's only there for test purposes.然后,当您在同一个项目中使用该类时,很明显(现在和将来)您不应该真正使用此方法 - 它仅用于测试目的。 This is a bit hacky, and not something I do myself, but it's at least worth consideration.这有点hacky,不是我自己做的,但至少值得考虑。

I'm using .NET Core 3.1.101 and the .csproj additions that worked for me were:我正在使用.NET Core 3.1.101和对我.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>

You can use private as well and you can call private methods with reflection.您也可以使用私有,并且可以通过反射调用私有方法。 If you're using Visual Studio Team Suite it has some nice functionality that will generate a proxy to call your private methods for you.如果您使用的是 Visual Studio Team Suite,它有一些不错的功能,可以生成代理来为您调用私有方法。 Here's a code project article that demonstrates how you can do the work yourself to unit test private and protected methods:这是一篇代码项目文章,演示了如何自己完成对私有和受保护方法进行单元测试的工作:

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

In terms of which access modifier you should use, my general rule of thumb is start with private and escalate as needed.就您应该使用哪个访问修饰符而言,我的一般经验法则是从 private 开始,并根据需要升级。 That way you will expose as little of the internal details of your class as are truly needed and it helps keep the implementation details hidden, as they should be.这样,您将尽可能少地公开真正需要的类的内部细节,并且有助于保持实现细节的隐藏,因为它们应该是。

In .NET Core 2.2, add this line to your Program.cs:在 .NET Core 2.2 中,将此行添加到您的 Program.cs 中:

using ...
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("MyAssembly.Unit.Tests")]

namespace
{
...

For .NET core you can add the attribute to the namespace as [assembly: InternalsVisibleTo("MyUnitTestsAssemblyName")].对于 .NET 核心,您可以将属性作为 [assembly: InternalsVisibleTo("MyUnitTestsAssemblyName")] 添加到命名空间。 eg Something like例如类似的东西

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

Add InternalsVisibleTo.cs file to project's root folder where .csproj file present.InternalsVisibleTo.cs文件添加到.csproj文件所在的项目根文件夹。

Content of InternalsVisibleTo.cs should be following InternalsVisibleTo.cs内容应该如下

using System.Runtime.CompilerServices;

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

starting from.Net 5, you can use also this syntax in the csproj of the project being tested:从 .Net 5 开始,您也可以在被测试项目的csproj中使用此语法:

  <ItemGroup>
    <InternalsVisibleTo Include="MyProject.Tests" />
  </ItemGroup>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM